Note that there are some explanatory texts on larger screens.

plurals
  1. POAutocomplete using nested form on has_many :through relationship
    text
    copied!<p>I'm currently using the nested_form gem (Ryan Bates) to add ingredients to a recipe using a nested form. All works well. My next goal is to add autocomplete to ingredients, but I'm stuck on how I should set this up.</p> <p>A recipe can have many ingredients, and an ingredient can have many recipes. I'm using a has_many :through relationship to manage the logic.</p> <p><strong>recipe.rb</strong></p> <pre><code> has_many :recipe_ingredients has_many :ingredients, through: :recipe_ingredients accepts_nested_attributes_for :ingredients, :reject_if =&gt; lambda { |a| a[:name].blank? }, allow_destroy: true attr_accessible :name, :desc, :ingredients_attributes validates_presence_of :name </code></pre> <p><strong>ingredient.rb</strong></p> <pre><code> has_many :recipe_ingredients has_many :recipes, through: :recipe_ingredients attr_accessible :name, :protein, :carbs, :fat, :ingredient_name validates_presence_of :name, :protein, :carbs, :fat def ingredient_name try(:name) end def ingredient_name=(name) Ingredient.find_by_name(name) if name.present? end </code></pre> <p><strong>recipe_ingredient.rb</strong></p> <pre><code> belongs_to :recipe belongs_to :ingredient attr_accessible :ingredient_id validates_presence_of :ingredient_id, :recipe_id </code></pre> <p><strong>recipes/_form.html.erb</strong></p> <pre><code>&lt;%= nested_form_for(@recipe) do |f| %&gt; &lt;% if @recipe.errors.any? %&gt; &lt;div id="error_explanation"&gt; &lt;h2&gt;&lt;%= pluralize(@recipe.errors.count, "error") %&gt; prohibited this recipe from being saved:&lt;/h2&gt; &lt;ul&gt; &lt;% @recipe.errors.full_messages.each do |msg| %&gt; &lt;li&gt;&lt;%= msg %&gt;&lt;/li&gt; &lt;% end %&gt; &lt;/ul&gt; &lt;/div&gt; &lt;% end %&gt; &lt;div class="field"&gt; &lt;%= f.label :name %&gt;&lt;br /&gt; &lt;%= f.text_field :name, placeholder: 'eg. Fajita Magic Sunrise' %&gt; &lt;/div&gt; &lt;div class="field"&gt; &lt;%= f.label :desc, 'Description' %&gt;&lt;br /&gt; &lt;%= f.text_area :desc, rows: 5, placeholder: 'Steps are useful here...' %&gt; &lt;/div&gt; &lt;h3&gt;Ingredients&lt;/h3&gt; &lt;%= f.fields_for :ingredients do |builder| %&gt; &lt;%= render "ingredient_fields", :f =&gt; builder %&gt; &lt;% end %&gt; &lt;p&gt;&lt;%= f.link_to_add "Add Ingredient", :ingredients %&gt;&lt;/p&gt; &lt;div class="actions"&gt; &lt;%= f.submit nil, class: 'button green' %&gt; or &lt;%= link_to 'go back', :back %&gt; &lt;/div&gt; &lt;% end %&gt; </code></pre> <p><strong>recipes/_ingredient_fields.html.erb</strong></p> <pre><code>&lt;div class="field"&gt; &lt;%= f.label :name, "Name" %&gt;&lt;br /&gt; &lt;%= f.text_field :ingredient_name, placeholder: 'Eg. 1 Scrambled Egg' %&gt; &lt;%= f.text_field :protein, placeholder: "Protein", size: 5 %&gt; &lt;%= f.text_field :carbs, placeholder: "Carbs", size: 5 %&gt; &lt;%= f.text_field :fat, placeholder: "Fat", size: 5 %&gt; &lt;%= f.link_to_remove "Remove" %&gt; &lt;/div&gt; </code></pre> <p><strong>development.log (when trying to add ingredients)</strong></p> <pre><code>Started PUT "/recipes/7" for 127.0.0.1 at 2012-03-10 12:53:15 -0600 Processing by RecipesController#update as HTML Parameters: {"utf8"=&gt;"✓", "authenticity_token"=&gt;"***", "recipe"=&gt;{"name"=&gt;"Next Recipe", "desc"=&gt;"Only one ingredient", "ingredients_attributes"=&gt;{"new_1331405592002"=&gt;{"ingredient_name"=&gt;"Beans", "protein"=&gt;"", "carbs"=&gt;"", "fat"=&gt;"", "_destroy"=&gt;"false"}}}, "commit"=&gt;"Update Recipe", "id"=&gt;"7"} Recipe Load (0.1ms) SELECT "recipes".* FROM "recipes" WHERE "recipes"."id" = ? LIMIT 1 [["id", "7"]] (0.0ms) begin transaction (0.0ms) commit transaction Redirected to http://***.dev/recipes/7 Completed 302 Found in 2ms (ActiveRecord: 0.2ms) </code></pre> <p>So! As you can see I set a new attribute named ingredient_name, and created a getter/setter method in ingredients.rb to pull it and set it if it exists. Basically, I think the problem is that I'm using has_many :through.</p> <p>It doesn't seem that what I have now would update the join table because the recipe isn't being passed to my setter method, so it wouldn't know which recipe to save it to anyway.</p> <p>So does the virtual attribute then need to be in the recipe model? As you can see, just really confused.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload