wejrowski
wejrowski

Reputation: 459

How to make comma separated ids turn to array in rails parameters like ids[] would

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

Answers (3)

skalee
skalee

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

hraynaud
hraynaud

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

jrochkind
jrochkind

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

Related Questions