faustinoaq changed the topic of #amber to: Welcome to Amber Framework community! | https://amberframework.org | Developer happiness, productivity and bare metal performance | GH: https://github.com/amberframework | Docs: https://docs.amberframework.org | Gitter: https://gitter.im/amberframework/amber | IRC Logger: https://irclog.whitequark.org/amber | Amber::Server.start
_whitelogger has joined #amber
_whitelogger has joined #amber
<FromGitter> <Sjoerrdd> and why can't i send validation errors as a json response?
feepbot has quit [Ping timeout: 252 seconds]
feepbot has joined #amber
<FromGitter> <marco-fp> can you be more specific? Why can't you?
<FromGitter> <marco-fp> would be awesome to be able to disable the npm build and webpack stuff from the new apps, btw.
<FromGitter> <Sjoerrdd> Nevermind, fixed it
<FromGitter> <Sjoerrdd> I'm creating a SPA, so I linked all routes to `HomeController, :index`
<FromGitter> <Sjoerrdd> But it's not possible to get my static files \o/
<FromGitter> <Sjoerrdd> because * goes to the controller, and * goes to the public path
<FromGitter> <Sjoerrdd> because (STAR) goes to the controller, and (STAR) goes to the public path*
<FromGitter> <marco-fp> I'd advice you to not use amber to serve the SPA
<FromGitter> <marco-fp> use nginx for that :)
<FromGitter> <marco-fp> and Amber for the api endpoints
<FromGitter> <marco-fp> it should be fast enough to cover you for low loads, but ideally you should use a dedicated server engine for that and not a single process/thread as Amber
<FromGitter> <drujensen> @Sjoerrdd The public path uses the static pipeline and is already defined so you don’t need to create your own. The recommended way to setup an API would be to use the following routes: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/amberframework/amber?at=5bbf60db3844923661202663]
<FromGitter> <drujensen> To access the api: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/amberframework/amber?at=5bbf61196e5a401c2d53b037]
<FromGitter> <drujensen> regarding the remote ip, there is an issue in Amber and Crystal to solve this. https://github.com/amberframework/amber/issues/955
<FromGitter> <drujensen> regarding amber watch and removing npm dependency, @faustinoaq is working on this. https://github.com/amberframework/amber/issues/476
<FromGitter> <drujensen> hope this helps
<FromGitter> <drujensen> @marco-fp is correct that using nginx is best for delivery of assets. I usually use docker compose and setup an nginx that maps a volume to the static assets.
<FromGitter> <drujensen> or you can push them to the edges of a CDN(content delivery network) for even better performance
<FromGitter> <drujensen> An example nginx vhost with reverse proxy to amber would look something like this: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/amberframework/amber?at=5bbf64bd6e5a401c2d53cd57]
<FromGitter> <drujensen> where `/app/user/public` would map a volume to your `/public` directory where your assets reside.
<FromGitter> <johansmitsnl> What am I missing: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/amberframework/amber?at=5bbf8c63ef4afc4f2858ba2c]
<FromGitter> <Blacksmoke16> try doing `Node.all(%("hostname" like ?), [hostname]).first`
<FromGitter> <Blacksmoke16> or `Node.all(%("nodes"."hostname" like ?), [hostname]).first`
<FromGitter> <Blacksmoke16> also you dont have `WHERE`
<FromGitter> <Blacksmoke16> `Node.all("WHERE hostname LIKE ?", [hostname]).first` thats prob the main issue
<FromGitter> <Blacksmoke16> @johansmitsnl
<FromGitter> <johansmitsnl> @Blacksmoke16 thnx, when I added the where I get this: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/amberframework/amber?at=5bbf8fadc7bf7c3662f47623]
<FromGitter> <johansmitsnl> thats because the result is empty (not in the db yet)
<FromGitter> <Blacksmoke16> make it `.first?` should return nil instead of raising
<FromGitter> <johansmitsnl> That did it, thnx 👍
<FromGitter> <Blacksmoke16> np
<FromGitter> <johansmitsnl> How would I override a setter for `Granite::Base` ⏎ ⏎ I want to downcase the email field in the model, I made this function: ⏎ ⏎ ```def email=(input) ⏎ @email = input.downcase ⏎ end``` ... [https://gitter.im/amberframework/amber?at=5bbf90e5271506518df5bddb]
<FromGitter> <Blacksmoke16> how are you calling it?
<FromGitter> <johansmitsnl> from the controller action (that was scaffold)
<FromGitter> <johansmitsnl> `account.set_attributes account_params.validate!`
<FromGitter> <Blacksmoke16> hmm sec
<FromGitter> <Blacksmoke16> ah
<FromGitter> <Thellior> @Blacksmoke16 I think that it actually should work if you look at https://github.com/amberframework/granite/blob/94449670835c3e4ce86991b9f304f27fe66875c0/src/granite/fields.cr#L148
<FromGitter> <Blacksmoke16> naw, iirc the `set_attributes` is skipping the setters
<FromGitter> <Blacksmoke16> and setting value directly
<FromGitter> <Thellior> O i see
<FromGitter> <Thellior> The @
<FromGitter> <Thellior> Sorry
<FromGitter> <Blacksmoke16> yea
<FromGitter> <Thellior> @johansmitsnl What you can do is use a before_save
<FromGitter> <Blacksmoke16> yea is what i was going to suggest
<FromGitter> <Thellior> ```code paste, see link``` [https://gitter.im/amberframework/amber?at=5bbf9297f659e677729c509a]
<FromGitter> <Thellior> @Blacksmoke16 Sorry i interfered
<FromGitter> <Blacksmoke16> you good :p
<FromGitter> <johansmitsnl> @Thellior ⏎ ⏎ ```Can't infer the type of instance variable '@title' of Account ⏎ ⏎ if title = @title``` [https://gitter.im/amberframework/amber?at=5bbf9304600c5f6423910176]
<FromGitter> <Thellior> if email = @email
<FromGitter> <Blacksmoke16> thats just an example code
<FromGitter> <Blacksmoke16> from the readme
<FromGitter> <Thellior> Indeed
<FromGitter> <Thellior> What @Blacksmoke16 said
<FromGitter> <Blacksmoke16> and change it down `downcase`
<FromGitter> <johansmitsnl> ```code paste, see link``` [https://gitter.im/amberframework/amber?at=5bbf9330bbdc0b250524cdb6]
<FromGitter> <Thellior> The error states that you don’t have a field called title
<FromGitter> <Thellior> That’s true right
<FromGitter> <Thellior> You have a field uuid and email
<FromGitter> <Thellior> In your case you want to downcase the email
<FromGitter> <johansmitsnl> WOW I need some time off the pc
<FromGitter> <Thellior> So the downcase_title method should be downcase_email
<FromGitter> <Thellior> And the if email = @email
<FromGitter> <Thellior> @email = email.downcase
<FromGitter> <Blacksmoke16> also know this will save the email in all lowercase only when you save it
<FromGitter> <Blacksmoke16> to the database*
<FromGitter> <johansmitsnl> that worked thnx
<FromGitter> <Thellior> No problemo
<FromGitter> <Thellior> It was more Blacksmoke
<FromGitter> <Thellior> I was just like
<FromGitter> <Thellior> I know this :P
<FromGitter> <Thellior> Lets me interfere
<FromGitter> <johansmitsnl> is there a reason why the setters are skipped? If I'm right in rails they are not skipped
<FromGitter> <Blacksmoke16> well this isnt rails
<FromGitter> <Blacksmoke16> and reason is because amber is using `set_attributes` directly
<FromGitter> <johansmitsnl> Learning this new framework
<FromGitter> <Thellior> I don’t think it was on purpose
<FromGitter> <Blacksmoke16> which skips the setters, and directly sets the values
<FromGitter> <Thellior> You see that we have @{{name.id}}
<FromGitter> <Thellior> So in the email example
<FromGitter> <Thellior> It will be @email = value.to_s
<FromGitter> <Thellior> So it’s not calling the method directly but assign the value directly
<FromGitter> <Blacksmoke16> `account.set_attributes account_params.validate!` after this line you could prob do your `account.email = "abc@gmail.com"` which *should* call your setter
<FromGitter> <Thellior> That also works
<FromGitter> <Thellior> We could also change it to use the setter instead
<FromGitter> <Thellior> We are creating the methods anyways
<FromGitter> <Blacksmoke16> ye, they should already be made by then
<FromGitter> <Thellior> And if people override them they get expected behaviour
<FromGitter> <Blacksmoke16> that whole cast_to_field needs redone anyway is a mess
<FromGitter> <Thellior> I will make a pull request
<FromGitter> <johansmitsnl> Understanding it now ⏎ I know it not Rails (thats why i'm learning it) but it looks a lot like it so there are some expectations that are different. And thats fine I'm just discovering them 😄
<FromGitter> <johansmitsnl> Thnx for now both
<FromGitter> <Blacksmoke16> @Thellior 👍
<FromGitter> <johansmitsnl> Is there for relations also a depended destroy? ⏎ I' m looking at these docs: https://docs.amberframework.org/amber/guides/models/granite/associations are these the right ones or do I have to look elsewhere?
<FromGitter> <johansmitsnl> I want to call: `http://0.0.0.0:3000/nodes.json` ⏎ But it says `The request was not found. GET - /nodes.json` ⏎ ⏎ In the controller I have: ⏎ ... [https://gitter.im/amberframework/amber?at=5bbf977d435c2a518e8db904]
<FromGitter> <Thellior> put .json to the end of the url if im correct
<FromGitter> <Thellior> Or set the content-type request header if im correct out of my head
<FromGitter> <Thellior> to application/json
<FromGitter> <robacarp> yeah, how are you calling that url? just plain in the browser won't work because it doesn't have the accepts header set to json
<FromGitter> <johansmitsnl> I did it in the browser yes
<FromGitter> <johansmitsnl> It does not look to the extension that is requested then?
<FromGitter> <robacarp> 1 sec, let me look this up
<FromGitter> <Thellior> @Blacksmoke16 Removing the @ will raise a lot of errors so i keep it like this for now
<FromGitter> <Blacksmoke16> 👍
<FromGitter> <johansmitsnl> When I do the request with the json accept header it returns the json indeed
<FromGitter> <johansmitsnl> What is the way to select only specific fields that you want to json? Now I have this: `nodes.to_json` but I want to have only `id, hostname` in the result.
<FromGitter> <robacarp> there is code here to switch based on file extension: https://github.com/amberframework/amber/blob/master/src/amber/controller/helpers/responders.cr#L88-L91
<FromGitter> <robacarp> I'm not sure why requesting with .json didn't work, I'd have to dig in
<FromGitter> <johansmitsnl> @robacarp thnx
<FromGitter> <robacarp> I feel like granite has something for that.....though it's probably under documented
<FromGitter> <johansmitsnl> could you give me some pointers where to look?
<FromGitter> <robacarp> easiest case is you can just make a hash and return what you want in it
<FromGitter> <robacarp> the granite test suite is where I'm looking
<FromGitter> <robacarp> @Blacksmoke16 is the most recent one to have worked on that stuff, I think
<FromGitter> <Blacksmoke16> @johansmitsnl you would have to override the `.to_json` on your model and build out the json yourself
<FromGitter> <Blacksmoke16> granite taps into the `JSON::Serializable` implementation, and thats not a feature atm
<FromGitter> <johansmitsnl> ` field password : String, json_options: {ignore: true} # skip this field in serialization and deserialization`
<FromGitter> <Blacksmoke16> https://github.com/crystal-lang/crystal/issues/6406 i made an issue about that but didnt seem to get too much support
<FromGitter> <Blacksmoke16> using ignore: true could be an option, just know that it would be ignored both ways
<FromGitter> <johansmitsnl> Defining it in ignore will work for now, but it will be later on an issue, because depending on the current user I want to expose more fields
<FromGitter> <Blacksmoke16> i.e. if you have a password field and do like `Model.from_json(%({"id":1, "password": "foo"}))` it wouldn't parse the `password` field into your object
<FromGitter> <Blacksmoke16> overriding the `.to_json` method and having logic in there would be best bet imo
<FromGitter> <Blacksmoke16> at least then you would retain the being able to get the fields from the json into your object, and manually do that to have better control over it
<FromGitter> <Blacksmoke16> i wish there was a better way to do stuff like this. is a major pita to do manually, esp with a lot of fields :/
<FromGitter> <johansmitsnl> Personally I like the serializer from rails https://github.com/rails-api/active_model_serializers
<FromGitter> <johansmitsnl> You can make the "view" as you desire
<FromGitter> <johansmitsnl> like the html ones
<FromGitter> <robacarp> @johansmitsnl I've done *essesntially* that on more than one occasion with Amber, but without the framework.
<FromGitter> <robacarp> something like
<FromGitter> <robacarp> ```code paste, see link``` [https://gitter.im/amberframework/amber?at=5bbf9e826e5a401c2d55c0e5]
<FromGitter> <robacarp> then in your view you can just do
<FromGitter> <robacarp> ```render do ⏎ json UserSerializer.serialize(user) ⏎ end``` [https://gitter.im/amberframework/amber?at=5bbf9ea8271506518df62735]
<FromGitter> <robacarp> that example is pretty smurfy, but you get the idea
<FromGitter> <johansmitsnl> @robacarp yes thats simular indeed
<FromGitter> <paulcsmith> One small tip: You can use a named tuple for slightly more concise serializers: `{id: user.id, name: user.name}`
<FromGitter> <robacarp> yes! tuples
<FromGitter> <robacarp> I've also done.....this
<FromGitter> <robacarp> ```json user.serialize(as: UserSerializer)``` [https://gitter.im/amberframework/amber?at=5bbfa2c71e23486b93b0be94]
<FromGitter> <paulcsmith> How do you handle serializing one v. many? In Lucky we suggest two classes `Users::ShowSerializer` and `Users::IndexSerializer` https://luckyframework.org/guides/writing-json-apis/#create-a-serializer
<FromGitter> <paulcsmith> But I wonder if you've tried something you like that works better
<FromGitter> <robacarp> my personal philosophy is that customized serializers should be avoided -- whatever a user object is, should always be a user object
<FromGitter> <robacarp> that way client devs dont have to have a user_from_show_deserializer and a user_from_index_deserializer
<FromGitter> <robacarp> so I'd just serialize the object into the array for #index
<FromGitter> <paulcsmith> That's basically what is done in most IndexSerializers, but I often need to add extra data, like the total count, what page you are on, total pages, etc. for the index
<FromGitter> <robacarp> oh, for sure, metadata
<FromGitter> <paulcsmith> How do you handle that?
<FromGitter> <robacarp> In Amber? unfortunately not well :<
<FromGitter> <robacarp> Granite doesn't really populate that stuff in a way that would be convienient to publish
<FromGitter> <paulcsmith> Oh I see. So for now are you doing something like this in index actions? `json users.map({ |user| UserSerializer.serialize(user) })` and leaving out metadata?
<FromGitter> <robacarp> essentially, yes
<FromGitter> <robacarp> well, you can't have an array at the top level in json right?
<FromGitter> <robacarp> { users: users.map(&.serialize UserSerializer) }
<FromGitter> <eliasjpr> Why not simply use https://crystal-lang.org/api/0.26.1/JSON/Serializable.html
<FromGitter> <robacarp> mostly, I didn't find it flexible enough
<FromGitter> <robacarp> even if I develop a consistent API serialization format, I still need a more verbose serializer for logging or internal apis
<FromGitter> <eliasjpr> there is a nice shard as well that does serialization
<FromGitter> <eliasjpr> Crind I believe is the name
<FromGitter> <drujensen> > naw, iirc the `set_attributes` is skipping the setters ⏎ @Blacksmoke16 we should fix this
<FromGitter> <drujensen> nm, just caught up that you were getting a bunch of errors
<FromGitter> <eliasjpr> https://github.com/c910335/crinder
<FromGitter> <drujensen> Would you use that with Crecto?
<FromGitter> <drujensen> Granite has json support: https://github.com/amberframework/granite/blob/master/docs/json_support.md
<FromGitter> <drujensen> I believe @Blacksmoke16 contributed this
<FromGitter> <drujensen> for paging meta-data, we should consider providing Link headers. http://www.rfc-editor.org/rfc/rfc5988.txt
<FromGitter> <drujensen> I’m not a fan of including metadata in the body json response
<FromGitter> <drujensen> ```code paste, see link``` [https://gitter.im/amberframework/amber?at=5bbfb37582893a2f3bcc4cee]
<robacarp> I'm all for link headers for sure
feepbot has quit [Ping timeout: 250 seconds]
feepbot has joined #amber