Jump to content

The ultimate community for Ruby on Rails developers.


Photo

:has_many :through with checkboxes and additional fields


  • Please log in to reply
3 replies to this topic

#1 Simply Misunderstood

Simply Misunderstood

    Passenger

  • Members
  • 7 posts

Posted 05 February 2014 - 04:15 PM

I can not seem to get this concept wrapped around my head.  I have a 3 models; a product model, an option model and then a product_options model that joins the two together.  The product_options table has an additional field called "cost".

 

The models are established like so:

Product.rb
has_many :product_options
has_many :options through: :product_options

accepts_nested_attributes_for :product_options, :reject_if => proc { |att| att.blank? }, :allow_destroy => true
Option.rb
has_many :product_options
has_many :products through: :product_options
ProductOption.rb
belongs_to :product
belongs_to :option

In my Product creation (and update) form I am trying to assign Options to my product using checkboxes.  I also want to pass the cost at the same time.  But I can not seem to get this to work.

 

How do I write the form so that I can have a list of all the options, with checkboxes and a text input field next to each.  Then I can check the checkbox for the options I want to associate with and fill in the text box for cost.  So that when I submit the correct options will be added to product_options with the cost column being populated with the correct information?

 

I scoured the web and can not find a straightforward answer.  There are plenty of responses from 2008 that are quite ugly and look hackish(sp?).  I keep thinking rails has to have a clean way of doing this.

 

My last attempt looks like this:

<%= f.fields_for :product_options do |po| %>
  <span class="ul">
    <% Option.all.each do |option| %>
      <label class="li">
        <%= pm.check_box :option %> 
        <%= option.name %> - <%= pm.text_field :cost %>
      </label><br />
    <% end %>
  </span>
<% end %>

It looks like it works, except this is what gets passed to the server (via parameters) no matter what I put in the text box.

"product_options"=>{"option"=>"0", "cost"=>""}},

For example, I checked the option with id #2, and put a cost of 1.00

 

I even tried this, and while it works for the checkboxes and appropriately creates the association it does not accept additional information (such as the cost column).

<%= check_box_tag :product_option_ids, option.id, @product.product_options.include?(option), :name => 'product[product_option_ids][]' %> 


#2 Simply Misunderstood

Simply Misunderstood

    Passenger

  • Members
  • 7 posts

Posted 05 February 2014 - 11:27 PM

Is this more difficult than I assume?



#3 Simply Misunderstood

Simply Misunderstood

    Passenger

  • Members
  • 7 posts

Posted 10 March 2014 - 04:20 PM   Best Answer

This was a lot easier then I was making it out to be.
 
In my controller I create the product_options.build methods for each option in the Options table like so:
 
 

     def create_options
      # product_options
      Option.active.each do |obj|
        if !@product.option_ids.include?(obj.id)
          @product.product_options.build(:option_id => obj.id)
        end
      end
     end

 
 
Then in my view, I display that list of checkboxes like so:
 
 

        <%= f.fields_for :product_options do |ff| %>
          <span class="ul">
              <label class="li">
                <%= ff.check_box :_destroy, {:checked => ff.object.persisted?}, '0', '1' %> 
                (note, I flipped the checkbox.  Checked == false and unchecked == true for _destroy method)
                <%= ff.hidden_field :option_id %> 
                <%= ff.object.option.name %> - <%= ff.text_field :cost %>
              </label><br />
          </span>
        <% end %>

 
 
My model stayed pretty much the same:
 
 

accepts_nested_attributes_for :product_options,       reject_if: proc { |att| att['option_id'].to_i == 0 },  allow_destroy: true

 
Then the options that are checked, are saved in the database automatically and atomically when product.save is called (no magic necessary in the create/update/destroy action).
 
Short, sweet and straight to the point.


  • Jamie likes this

#4 sidk

sidk

    Dispatcher

  • Members
  • 42 posts

Posted 07 December 2015 - 06:17 PM

For anyone coming by here looking for more details/help, I've written a brief article at http://ducktypelabs....the-join-table/

 

This article covers the various pieces you need to have in place to get this working in your app, and includes an example app to illustrate.


Improve your Rails knowledge with me at http://ducktypelabs.com





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users