0
class OptionValue
    has_and_belongs_to_many :listings, join_table: 'listing_options'
    belongs_to :type

class Listing
    has_and_belongs_to_many :option_values, join_table: 'listing_options'
    accepts_nested_attributes_for :option_values

I've looked at several questions here on the same topic, however in all those questions the asker wants additional functionality on the relationship and goes with the :through instead. I am looking to add values to the join table using the accepts_nested_attributes.

A listing has an option value for each option type. After processing the params received from the form they look like this:

listing_params => { "option_values_attributes"=> [{"option_value"=>"3"}, {"option_value"=>"5"}, {"option_value"=>"9"}]}

Calling Listing.new(listing_params) in create gives the error message

Unpermitted parameters: option_values
ActiveRecord::UnknownAttributeError: unknown attribute: option_value

Other attributes are successfully saved to the new listing instance. I've also tried option_value_id as parameter with the same result, and including @listing.option_values.build in new doesn't make a difference. I could convert the relationship to a :through relationship, but I do not need that type of relationship and would expect the HABTM to be more efficient otherwise. Is there something else I'm missing in the parameters, or should I change the relationship type to :through?

edit - relevant controller code

def create
  *binding.pry*
  @listing = Spree::Listing.new(listing_params)
  # @listing.save
def new
  @listing = Listing.new
  @listing.option_values.build

def listing_params
  params[:listing][:option_values_attributes] = []
  ovs = params[:listing][:option_values].values
  ovs.each do |ov|
    params[:listing][:option_values_attributes] << {"option_value" => ov}
  end
  params.require(:listing).permit(permitted_listing_attributes)
end

def permitted_listing_attributes
  [ :listing_options_attributes => [[:option_value_id]]] ]
end

edit - I now believe adding to the join table via accepts_nested_attributes is not supported in rails. Passing the option value ids as such raises an error. When instantiating a new listing (below), passing the type_id does not raise an error, indicating that we could use the accepts_nested_attributes with HABTM to create new option values, but not for adding only to the join table.

Listing.new({state: "1", "option_values_attributes" => [{"type_id" =>"30"}] })
bjorn
  • 175
  • 2
  • 9
  • Could you post your controller information, more specifically where you whitelist the strong parameters (`listing_params`)? – jkeuhlen Jul 28 '14 at 17:41
  • The params given above are what's returned from calling listing_params. Here is the relevant permitted attributes: def permitted_listing_attributes [ :listing_options_attributes => [[:option_value_id]]] ] end – bjorn Jul 28 '14 at 17:48
  • It looks like you aren't utilizing strong parameters properly. I'll update my answer with more information. – jkeuhlen Jul 28 '14 at 17:51
  • Do you have `accepts_nested_attributes_for :option_values` in your `listing` model? seems like you don't have it. – Pavan Jul 28 '14 at 17:52
  • @Pavan - yes, updated that in the question. – bjorn Jul 28 '14 at 18:18
  • @jkeuhlen - I've looked at the docs, will check out the railscast you linked to. – bjorn Jul 28 '14 at 18:18
  • Your controller code would be very useful.Can you post it? – Pavan Jul 28 '14 at 18:19
  • @bjorn You aren't using strong parameters correctly. Take a look at [this other SO post](http://stackoverflow.com/questions/18436741/rails-4-strong-parameters-nested-objects) if the railscast doesn't help. – jkeuhlen Jul 28 '14 at 18:44
  • @jkeuhlen - could you be more specific on what's not right with the strong parameters? I had looked through the documentation & many SO questions to get the parameters working and they are returning the correct results. I've just done some more testing on them and only scalar values matching the option_value key pass the params. If anything I may need to have the parameters in a different format to be accepted as attributes for the listing model. – bjorn Jul 28 '14 at 19:04

1 Answers1

1

If you haven't already, take a look at the docs for accepts_nested_attributes.

You need to include the parameters for OptionValue you are wanting to update in the params for Listing.

Another resource other than the docs: an excellent railscasts.

Your notion that HABTM is "more efficient" than a has_many :through is false. In fact, if you dig into the way rails implements HABTM, you'll see that it just creates another has_many :through. An easy way to see this is to reflect_on_all_associations() for one of your classes. You won't see a has_and_belongs_to_many relationship but you will see an association for has_many :through a join table and a has_many for a relationship to the join table. If you know how to solve this problem using :through instead, just make the switch.

jkeuhlen
  • 4,401
  • 23
  • 36
  • Pro tip: never use HABTM relationships. It is confusing for no good reason. Has many through is better. – ruby_newbie Jul 29 '14 at 02:04
  • @ruby_newbie Agree except sometimes if all you need is really simple many to many with no nesting or anything else HABTM is faster. – jkeuhlen Jul 29 '14 at 02:07
  • Does seem rather confusing. So I've tried out the reflect_on_all_associations() on listings and don't see a through: relationship for the listing_options. Will likely switch over to through: tomorrow. @macro=:has_and_belongs_to_many, @name=:option_values, @options={:join_table=>:listing_options, :autosave=>true}, @plural_name="option_values", – bjorn Jul 29 '14 at 04:38