我目前正在使用nested_form gem(Ryan Bates)使用嵌套表单向配方中添加成分。一切顺利。我的下一个目标是为成分添加自动完成功能,但我仍然坚持要如何设置它。
配方可以含有许多成分,而配料可以有很多配方。我正在使用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
ingredient.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
配方/ _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 %>
配方/ _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)
原来如此!如您所见,我设置了一个名为ingredient_name的新属性,并在ingredients.rb中创建了一个getter / setter方法来拉取它并设置它(如果存在)。基本上,我认为问题是我正在使用has_many:through。
似乎我现在没有更新连接表,因为配方没有传递给我的setter方法,因此无论如何它都不知道将它保存到哪个配方。
那么虚拟属性是否需要在配方模型中?正如你所看到的,真的很困惑。