使用 belongs_to 关系进行编辑
Edit with a belongs_to relationship
问题
我在编辑具有 belongs_to 关系 (extra_guest belongs_to age_table) 的表单时遇到问题。
我可以创建一个新的 extra_guest 并将其分配给一个 age_table,但是我无法让 edit/update 作为我的更新函数 returns a falseClass.--> @extra_guest.update(extra_guest_params).errors.full_messages
returns undefined method `errors' for false:FalseClass
代码
型号
class ExtraGuest < ApplicationRecord
belongs_to :age_table
validates :age_table, presence: true
end
class AgeTable < ApplicationRecord
belongs_to :park
has_many :extra_guests, dependent: :destroy
validates :name, :age_from, :age_to, presence: true
validates_associated :extra_guests
end
class Attraction < ApplicationRecord
belongs_to :park
has_many :extra_guests, dependent: :destroy
accepts_nested_attributes_for :extra_guests, allow_destroy: true
validates :name, presence: true
end
class Park < ApplicationRecord
has_many :attractions, dependent: :destroy
has_many :age_tables, dependent: :destroy
validates :name, :currency, presence: true
end
extra_guests_controller
def edit
@extra_guest = ExtraGuest.find(params[:id])
@age_table = @extra_guest.age_table
@age_table_list = AgeTable.where(park: @attraction.park)
end
def update
@extra_guest = @attraction.extra_guests.find(params[:id])
@age_table = AgeTable.find(params[:age_table])
authorize @extra_guest
if @extra_guest = @extra_guest.update(extra_guest_params)
redirect_to root_path
else
@attraction = Attraction.find(params[:attraction_id])
@extra_guest = ExtraGuest.find(params[:id])
@age_table_list = @attraction.park.age_tables
render 'edit'
end
end
private
def extra_guest_params
params.require(:extra_guest).permit(:name, :age_table_id,
extra_guest_prices_attributes: [:id, :name, :price_type, :start_date, :end_date, :price, :duration, :duration_min, :duration_max, :backend_only, :weekend_extra, :_destroy])
end
views/extra_guests/form
<%= simple_form_for [@attraction, @extra_guest] do |f|%>
<%= f.input :age_table, :as => :select, :selected => @age_table.id, :collection => @age_table_list.map {|u| [u.name, u.id]}, :include_blank => false %>
<% f.button :submit %>
错误信息+参数
Couldn't find AgeTable without an ID
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"l8HMnVIRybZg==",
"extra_guest"=>
{"age_table"=>"104",
"extra_guest_prices_attributes"=>
{"0"=>{"price"=>"1.0", "weekend_extra"=>"", "start_date"=>"2019-10-15", "end_date"=>"20-09-2019", "duration"=>"", "duration_min"=>"", "duration_max"=>"", "_destroy"=>"false", "id"=>"42"},
"1"=>{"price"=>"1.0", "weekend_extra"=>"", "start_date"=>"2019-10-15", "end_date"=>"2019-10-16", "duration"=>"", "duration_min"=>"", "duration_max"=>"", "_destroy"=>"false", "id"=>"43"}}},
"commit"=>"Save new option",
"attraction_id"=>"185",
"id"=>"55"}
在我看来,您似乎在定义 @attraction 之前尝试使用它。您可以通过在方法中进一步移动您对 @attraction 的定义来解决此问题,但我会将其移动到它自己的方法中,如下所示:
private
def attraction
@attraction ||= Attraction.find(params[:attraction_id])
end
然后你使用方法名,现在为整个控制器定义并在你使用它时调用它(与实例变量相反,如果你调用它而不定义它,它只会是 'nil') . ||= 允许方法 return 实例变量的现有值(如果已定义),而不是 运行 每次调用方法时查询。所以你的更新操作的第一行是
@extra_guest = attraction.extra_guests.find(params[:id])
我会为您那里的其他实例变量做类似的事情(@extra_guest、@age_table 和@age_table_list 应该在私有方法中单独定义)。顺便说一句,为单个控制器使用大量实例变量(你在这个控制器中有 4 个,很多)被认为有点代码味道,但你应该先做一些能工作的东西,然后再重构。以后参考:https://thoughtbot.com/blog/sandi-metz-rules-for-developers
首先,你说这段代码有误@extra_guest.update(extra_guest_params).errors.full_messages
但是你显示的代码没有那一行。
现在,update
方法 returns 如果失败则返回 false https://apidock.com/rails/ActiveRecord/Persistence/update
这一行:
@extra_guest = @extra_guest.update(extra_guest_params)
如果失败会设置@extra_guest为false,不需要设置@extra_guest,直接使用if @extra_guest.update(extra_guest_params)
即可
使用你命名的代码行,但它不在你显示的代码中,@extra_guest.update(extra_guest_params).errors.full_messages
,如果有错误,那么 @extra_guest.update(extra_guest_params)
将是错误的,所以没有 .errors
方法找到了。
你必须把它分成两行:
@extra_guest.update(extra_guest_params) # after this, @extra_guest will have the errors hash set
@extra_guest.errors.full_messages # call it on the object and not on the result value from the update method
编辑:您允许 age_table_id
但参数是 age_table
,将参数的名称也修改为 age_table_id
问题
我在编辑具有 belongs_to 关系 (extra_guest belongs_to age_table) 的表单时遇到问题。
我可以创建一个新的 extra_guest 并将其分配给一个 age_table,但是我无法让 edit/update 作为我的更新函数 returns a falseClass.--> @extra_guest.update(extra_guest_params).errors.full_messages
returns undefined method `errors' for false:FalseClass
代码
型号
class ExtraGuest < ApplicationRecord
belongs_to :age_table
validates :age_table, presence: true
end
class AgeTable < ApplicationRecord
belongs_to :park
has_many :extra_guests, dependent: :destroy
validates :name, :age_from, :age_to, presence: true
validates_associated :extra_guests
end
class Attraction < ApplicationRecord
belongs_to :park
has_many :extra_guests, dependent: :destroy
accepts_nested_attributes_for :extra_guests, allow_destroy: true
validates :name, presence: true
end
class Park < ApplicationRecord
has_many :attractions, dependent: :destroy
has_many :age_tables, dependent: :destroy
validates :name, :currency, presence: true
end
extra_guests_controller
def edit
@extra_guest = ExtraGuest.find(params[:id])
@age_table = @extra_guest.age_table
@age_table_list = AgeTable.where(park: @attraction.park)
end
def update
@extra_guest = @attraction.extra_guests.find(params[:id])
@age_table = AgeTable.find(params[:age_table])
authorize @extra_guest
if @extra_guest = @extra_guest.update(extra_guest_params)
redirect_to root_path
else
@attraction = Attraction.find(params[:attraction_id])
@extra_guest = ExtraGuest.find(params[:id])
@age_table_list = @attraction.park.age_tables
render 'edit'
end
end
private
def extra_guest_params
params.require(:extra_guest).permit(:name, :age_table_id,
extra_guest_prices_attributes: [:id, :name, :price_type, :start_date, :end_date, :price, :duration, :duration_min, :duration_max, :backend_only, :weekend_extra, :_destroy])
end
views/extra_guests/form
<%= simple_form_for [@attraction, @extra_guest] do |f|%>
<%= f.input :age_table, :as => :select, :selected => @age_table.id, :collection => @age_table_list.map {|u| [u.name, u.id]}, :include_blank => false %>
<% f.button :submit %>
错误信息+参数
Couldn't find AgeTable without an ID
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"l8HMnVIRybZg==",
"extra_guest"=>
{"age_table"=>"104",
"extra_guest_prices_attributes"=>
{"0"=>{"price"=>"1.0", "weekend_extra"=>"", "start_date"=>"2019-10-15", "end_date"=>"20-09-2019", "duration"=>"", "duration_min"=>"", "duration_max"=>"", "_destroy"=>"false", "id"=>"42"},
"1"=>{"price"=>"1.0", "weekend_extra"=>"", "start_date"=>"2019-10-15", "end_date"=>"2019-10-16", "duration"=>"", "duration_min"=>"", "duration_max"=>"", "_destroy"=>"false", "id"=>"43"}}},
"commit"=>"Save new option",
"attraction_id"=>"185",
"id"=>"55"}
在我看来,您似乎在定义 @attraction 之前尝试使用它。您可以通过在方法中进一步移动您对 @attraction 的定义来解决此问题,但我会将其移动到它自己的方法中,如下所示:
private
def attraction
@attraction ||= Attraction.find(params[:attraction_id])
end
然后你使用方法名,现在为整个控制器定义并在你使用它时调用它(与实例变量相反,如果你调用它而不定义它,它只会是 'nil') . ||= 允许方法 return 实例变量的现有值(如果已定义),而不是 运行 每次调用方法时查询。所以你的更新操作的第一行是
@extra_guest = attraction.extra_guests.find(params[:id])
我会为您那里的其他实例变量做类似的事情(@extra_guest、@age_table 和@age_table_list 应该在私有方法中单独定义)。顺便说一句,为单个控制器使用大量实例变量(你在这个控制器中有 4 个,很多)被认为有点代码味道,但你应该先做一些能工作的东西,然后再重构。以后参考:https://thoughtbot.com/blog/sandi-metz-rules-for-developers
首先,你说这段代码有误@extra_guest.update(extra_guest_params).errors.full_messages
但是你显示的代码没有那一行。
现在,update
方法 returns 如果失败则返回 false https://apidock.com/rails/ActiveRecord/Persistence/update
这一行:
@extra_guest = @extra_guest.update(extra_guest_params)
如果失败会设置@extra_guest为false,不需要设置@extra_guest,直接使用if @extra_guest.update(extra_guest_params)
使用你命名的代码行,但它不在你显示的代码中,@extra_guest.update(extra_guest_params).errors.full_messages
,如果有错误,那么 @extra_guest.update(extra_guest_params)
将是错误的,所以没有 .errors
方法找到了。
你必须把它分成两行:
@extra_guest.update(extra_guest_params) # after this, @extra_guest will have the errors hash set
@extra_guest.errors.full_messages # call it on the object and not on the result value from the update method
编辑:您允许 age_table_id
但参数是 age_table
,将参数的名称也修改为 age_table_id