Автозаполнение с использованием вложенной формы в отношении has_many: through - PullRequest
1 голос
/ 10 марта 2012

В настоящее время я использую самоцвет nested_form (Райан Бейтс), чтобы добавить ингредиенты в рецепт, используя вложенную форму.Все работает хорошо.Моя следующая цель - добавить автозаполнение к ингредиентам, но я застрял на том, как мне это настроить.

В рецепте может быть много ингредиентов, а в ингредиенте может быть много рецептов.Я использую отношение has_many: through для управления логикой.

recipe.rb

  has_many :recipe_ingredients
  has_many :ingredients, through: :recipe_ingredients

  accepts_nested_attributes_for :ingredients, :reject_if => lambda { |a| a[:name].blank? }, allow_destroy: true

  attr_accessible :name, :desc, :ingredients_attributes

  validates_presence_of :name

ингридиент.rb

  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

recipe_ingredient.rb

  belongs_to :recipe
  belongs_to :ingredient

  attr_accessible :ingredient_id

  validates_presence_of :ingredient_id, :recipe_id

recipes / _form.html.erb

<%= nested_form_for(@recipe) do |f| %>
  <% if @recipe.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@recipe.errors.count, "error") %> prohibited this recipe from being saved:</h2>

      <ul>
      <% @recipe.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, placeholder: 'eg. Fajita Magic Sunrise' %>
  </div>
  <div class="field">
    <%= f.label :desc, 'Description' %><br />
    <%= f.text_area :desc, rows: 5, placeholder: 'Steps are useful here...' %>
  </div>

  <h3>Ingredients</h3>
  <%= f.fields_for :ingredients do |builder| %>
      <%= render "ingredient_fields", :f => builder %>
  <% end %>
  <p><%= f.link_to_add "Add Ingredient", :ingredients %></p>

  <div class="actions">
    <%= f.submit nil, class: 'button green' %> or <%= link_to 'go back', :back %>
  </div>
<% end %>

recipes/_ingredient_fields.html.erb

<div class="field">
  <%= f.label :name, "Name" %><br />
  <%= f.text_field :ingredient_name, placeholder: 'Eg. 1 Scrambled Egg' %> 
  <%= f.text_field :protein, placeholder: "Protein", size: 5 %>
  <%= f.text_field :carbs, placeholder: "Carbs", size: 5 %>
  <%= f.text_field :fat, placeholder: "Fat", size: 5 %>
  <%= f.link_to_remove "Remove" %>
</div>

development.log (при попытке добавления ингредиентов)

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"=>"✓", "authenticity_token"=>"***", "recipe"=>{"name"=>"Next Recipe", "desc"=>"Only one ingredient", "ingredients_attributes"=>{"new_1331405592002"=>{"ingredient_name"=>"Beans", "protein"=>"", "carbs"=>"", "fat"=>"", "_destroy"=>"false"}}}, "commit"=>"Update Recipe", "id"=>"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)

Итак!Как вы можете видеть, я установил новый атрибут с именем component_name и создал метод getter / setter в ингредиентов.rb, чтобы извлечь его и установить, если он существует.По сути, я думаю, что проблема в том, что я использую has_many: through.

Не похоже, что то, что у меня сейчас есть, обновит таблицу соединений, потому что рецепт не передается моему методу установки,так что он не будет знать, в какой рецепт его сохранить, в любом случае.

Так должен ли виртуальный атрибут быть в модели рецепта?Как видите, просто очень запутался.

...