我是新手。我正在尝试开发一个涉及商店和糖果的简单Web应用程序,其中商店可以有很多糖果。
我的shop / show.html.erb中有以下代码,该代码两次显示糖果列表。
<% i=0 %>
<% for candy in @shop.candies do %>
<% i+=1 %>
<%= i %> <%= candy.name %>
<% end %>
<%= form_for([@shop, @shop.candies.build]) do |f| %>
<%= render(:partial => 'form',
:locals => {:f => f, :header => "Add a Candy",
:placeholder => "Enter a candy name"}) %>
<% end %>
<% i=0 %>
<% for candy in @shop.candies do %>
<% i+=1 %>
<%= i %> <%= candy.name %>
<% end %>
我在_form.html.erb中创建新糖果的代码:
<%= f.text_field(:name, :placeholder=> placeholder, :class=>"form-control custom-input")%>
<%= button_tag( :class => "btn btn-primary mb-2 btn-custom btn-custom-sc") do %>
<i class="fas fa-plus icon"></i>
<% end %>
商店代码控制者:
class ShopsController < ApplicationController
def show
@shop = Shop.find(params[:id])
@unshelved_candies = @shop.candies.unshelved_candies
end
private
def shop_params
params.require(:shop).permit(:name)
end
end
糖果控制器代码:
class CandiesController < ApplicationController
def create
@shop = Shop.find(params[:shop_id])
@candy = @shop.candies.create(candy_params)
redirect_to(shop_path(@shop))
end
private
def candy_params
params.require(:candy).permit(:name)
end
end
end
当我运行代码并在浏览器上查看时,我注意到它在第二个循环中创建了一个空糖(不在数据库中)。但是,当我删除用于创建糖果的表单时,它的行为应达到预期。我无法理解为什么它又要循环一次并显示空白值。 第一个循环的输出是正确的:
第二个循环的输出是:
有人可以告诉我为什么它在第二个循环中显示空白值以及如何防止这种额外的迭代吗?
答案 0 :(得分:3)
我相信“额外”糖果就是您要在此处实例化的糖果:
<%= form_for([@shop, @shop.candies.build]) do |f| %>
新糖果的糖果名称为nil,因此您将获得空白。
顺便说一句,这个:
<% i=0 %>
<% for candy in @shop.candies do %>
<% i+=1 %>
<%= i %> <%= candy.name %>
<% end %>
让我惊叹为非惯用的红宝石。我希望看到更多类似的东西:
<% @shop.candies.each.with_index(1) do |candy, index| %>
<%= index %> <%= candy.name %>
<% end %>
我想确保您不会得到多余糖果的蛮力方式是做类似的事情:
<% @shop.candies.each.with_index(1) do |candy, index| %>
<% unless candy.new_record? %>
<%= index %> <%= candy.name %>
<% end %>
<% end %>
您也可以尝试:
<%= form_for([@shop, @candy]) do |f| %>
我相信可以写成这样:
<%= form_for(@shop, @candy) do |f| %>
如果您想节省几个按键(它们随着时间的推移会累加)。
然后在您的ShopsController
中执行:
class ShopsController < ApplicationController
def show
@shop = Shop.find(params[:id])
@candy = Candy.new
@unshelved_candies = @shop.candies.unshelved_candies
end
private
def shop_params
params.require(:shop).permit(:name)
end
end
这也很好,因为它避免了:
@shop.candies.build
这要求您的view
对shop
和candies
之间的关系有很多了解,还要求您的view
直接与数据库进行交互。
由于您显然正在使用嵌套路由,因此您可能需要查看shallow: true指令。
(这与您的问题无关),您可能想对Law of Demeter有所考虑。我注意到您这样做:
@unshelved_candies = @shop.candies.unshelved_candies
我个人想做些类似的事情:
@unshelved_candies = @shop.unshelved_candies
在Shop
中,您可能会有类似的内容:
class Shop < ApplicationRecord
def unselved_candies
candies.unshelved
end
end
在Candy
中,类似:
class Candy < ApplicationRecord
class < self
def unshelved
where(shelved: false) # or however you determine a candy is unshelved
end
end
end
许多人会将unshelved
设为scope
,这是做同一件事的另一种方式。
这样,您的ShopsController
对商店和糖果之间的关系和搁置状态的机制了解得更少。 FWIW。