Reputation: 459
So the normal way would be to have multiple input fields with a name of "obj_ids[]", then the values in rails ends up magically zipping them into an array.
Does rails have some secret way of alternately doing this with simply one field?
I'm needing to separate the input fields from the actual form, and so right now I'm basically grabbing them all, and running a JS join on them to send as one field in a separate form. I could duplicate them all as hidden fields but that seems a bit much. Also obviously could do a split in the controller, but I'm curious if there's another way.
Upvotes: 1
Views: 2203
Reputation: 12665
Adding another setter to model (or overriding existing one) as suggested by @hraynaud is one possibility. However in my opinion supporting some non-standard input format is more a controller's duty than model's. Therefore, I wouldn't put that logic into a model.
Instead, I'd introduce another controller's method which returns preprocessed parameters. Works great with Strong Parameters.
protected
def preprocessed_params
p = params.deep_dup
p[:obj_ids] = p[:obj_ids].split(",") if p[:obj_ids]
p
end
def permitted_params
preprocessed_params.permit(:obj_ids => [])
end
This snippet could be further modified by using alias_method_chain
so that the preprocessed params are accessible via params
whereas the raw ones are kept in params_without_preprocessing
or something.
Upvotes: 0
Reputation: 746
Depending on your specific needs there are tons of ways to do this kind of thing in rails
hacking the params as @jrochkind has mentioned is one way but there are several more elegant solutions
create a virtual attribute in your model
class SomeModel
attr_reader :my_field
def my_field= value_as_comma_delimited_string
# here the the_field_i_really_want_set is an array type which is supported in mongo and postgres for exampld
self.the_field_i_really_want_set = value_as_comma_delimited_string.split(",")
end
end
You could do basically the same thing in a before_validation callback in this case you don't need to create an accessor
class User < ActiveRecord::Base
before_validation :normalize_name, on: :create
protected
def normalize_name
self.name = self.name.downcase.titleize # or whatever transformation you need
end
end
Another technique that I've been finding very useful and that is similar to the first one I showed is to override the accessor method directly. Here my_field is the actual field in your model's schema.
class SomeModel
def my_field= value_as_comma_delimited_string
self.write_attribute(:my_field,value_as_comma_delimited_string.split(","))
end
end
Upvotes: 1
Reputation: 23317
I don't think there's another way, I've looked into it before, for other cases.
For your case, if I understand right, you are constructing a form with JS and submitting the form with JS, and it's up to you whether to construct the form with multiple values mashed together in one input (which will turn into one URL query parameter) separated by commas, or separate fields/params.
I'd just go with separate fields/params.
Otherwise, on the controller side, you could do it in a before_filter rather than just the action method, even in a before_filter on your application_controller that applies to all actions, and you can even have the before_filter mutate Rails own params hash.
before_filter :split_commas
def split_commas
params[:my_field] = params[:my_field].split(",")
end
That should work, although mutating params hash like that has been the cause of so many frustrating bugs for me that I'm loathe to ever do it.
Upvotes: 0