rails before_create 在渲染时导致 nil id 'show' 创建视图 post
rails before_create causing nil id when rendering 'show' view from create post
我有一个 rails 模型,belongs_to 一个父 class。当提交 'new' 视图表单时,对 #create 进行 post 以插入新模型。在 model.rb 中,我有一个 before_create 回调,用于设置字段的起始值。在模型控制器创建方法中,我创建记录并重定向到新记录的 'show' 视图。问题是传递给 url 的记录 ID 始终为零。 如果我注释掉 before_create 语句,那么它每次都有效。 我在这里缺少什么?另外,为字段设置起始值的最佳方法是什么?我在 db 模型迁移或验证中猜测,但 before_create 方法似乎适用于此功能
@service = @account.services.create
(0.2ms) SAVEPOINT active_record_1
(0.2ms) RELEASE SAVEPOINT active_record_1
=> #<Service id: nil, account_id: 31, date: nil, default_lawn_cost: nil, cost: nil, description: nil, created_at: "2015-05-02 16:48:39", updated_at: "2015-05-02 16:48:39", paid: false>
>> @customer.accounts.create
(0.2ms) SAVEPOINT active_record_1
SQL (0.6ms) INSERT INTO "accounts" ("customer_id", "created_at", "updated_at", "total", "active") VALUES (?, ?, ?, ?, ?) [["customer_id", 14], ["created_at", "2015-05-02 16:48:50.524798"], ["updated_at", "2015-05-02 16:48:50.524798"], ["total", 0.0], ["active", "t"]]
(0.1ms) RELEASE SAVEPOINT active_record_1
=> #<Account id: 34, customer_id: 14, default_address: nil, address: nil, city: nil, state: nil, zip: nil, balance: nil, lawn_cost: nil, created_at: "2015-05-02 16:48:50", updated_at: "2015-05-02 16:48:50", note: nil, active: true, total: #<BigDecimal:4d3a668,'0.0',9(36)>, tax: nil>
class ServicesController < ApplicationController
def new
setup
@service = @account.services.build
end
def create
@customer = Customer.find(params[:customer_id])
@account = @customer.accounts.find(params[:account_id])
@service = @account.services.create(service_params)
if @service.valid?
add_service_to_account(@account, @service)
@account.save
redirect_to customer_account_service_path(@customer, @account, @service)
else
render 'new'
end
end
end
class Service < ActiveRecord::Base
belongs_to :account
before_create :unset_paid
validates :cost, format: { allow_blank: true, with: /\A$?\d{1,4}(\.\d{0,2})?\Z/ }
def unset_paid
self.paid = false
end
end
这是视图错误:
ActionController::UrlGenerationError in ServicesController#create
No route matches {:account_id=>"31", :action=>"show", :controller=>"services", :customer_id=>"14", :id=>nil} missing required keys: [:id]
Extracted source (around line #21):
第 21 行
redirect_to customer_account_service_path(@customer, @account, @service)
相关路线:
new_customer_account_service GET /customers/:customer_id/accounts/:account_id/services/new(.:format) services#new
edit_customer_account_service GET /customers/:customer_id/accounts/:account_id/services/:id/edit(.:format) services#edit
customer_account_service GET /customers/:customer_id/accounts/:account_id/services/:id(.:format) services#show
PATCH /customers/:customer_id/accounts/:account_id/services/:id(.:format) services#update
PUT /customers/:customer_id/accounts/:account_id/services/:id(.:format) services#update
DELETE /customers/:customer_id/accounts/:account_id/services/:id(.:format) services#destroy
class CreateServices < ActiveRecord::Migration
def change
create_table :services do |t|
t.references :account, index: true, foreign_key: true
t.date :date
t.boolean :default_lawn_cost
t.decimal :cost
t.string :description
t.timestamps null: false
end
end
end
这就是我不喜欢 ActiveRecord 回调的部分原因;他们太聪明了,会制造一些奇怪的情况,让你对一些没有明确原因的错误感到不安。
如果before_create
或before_save
回调returnsfalse
,它将取消即将执行的数据库操作。 请参阅 this guide page 了解其工作原理。我猜这就是在这种情况下让您感到困惑的原因,因为一旦您尝试创建记录,就会调用 unset_paid
记录并意外取消整个 save/create 操作。反过来,这意味着新的未创建记录没有 id
,因此当您尝试重定向到记录的 URL 时,路径变为 /accounts/nil
.
最近在 Rails 世界流传着这样的建议,即您应该始终默认使用 save!
和 create!
,而不是它们的 un-banged 版本,因为前者会引发如果操作失败则报错。如果您使用了 @account.save!
,您会立即看到一个异常,将您指向问题的核心(即,在尝试保存记录时出现问题),而不是让您怀疑您的路线是否被施了魔法。
希望对您有所帮助!
我有一个 rails 模型,belongs_to 一个父 class。当提交 'new' 视图表单时,对 #create 进行 post 以插入新模型。在 model.rb 中,我有一个 before_create 回调,用于设置字段的起始值。在模型控制器创建方法中,我创建记录并重定向到新记录的 'show' 视图。问题是传递给 url 的记录 ID 始终为零。 如果我注释掉 before_create 语句,那么它每次都有效。 我在这里缺少什么?另外,为字段设置起始值的最佳方法是什么?我在 db 模型迁移或验证中猜测,但 before_create 方法似乎适用于此功能
@service = @account.services.create
(0.2ms) SAVEPOINT active_record_1
(0.2ms) RELEASE SAVEPOINT active_record_1
=> #<Service id: nil, account_id: 31, date: nil, default_lawn_cost: nil, cost: nil, description: nil, created_at: "2015-05-02 16:48:39", updated_at: "2015-05-02 16:48:39", paid: false>
>> @customer.accounts.create
(0.2ms) SAVEPOINT active_record_1
SQL (0.6ms) INSERT INTO "accounts" ("customer_id", "created_at", "updated_at", "total", "active") VALUES (?, ?, ?, ?, ?) [["customer_id", 14], ["created_at", "2015-05-02 16:48:50.524798"], ["updated_at", "2015-05-02 16:48:50.524798"], ["total", 0.0], ["active", "t"]]
(0.1ms) RELEASE SAVEPOINT active_record_1
=> #<Account id: 34, customer_id: 14, default_address: nil, address: nil, city: nil, state: nil, zip: nil, balance: nil, lawn_cost: nil, created_at: "2015-05-02 16:48:50", updated_at: "2015-05-02 16:48:50", note: nil, active: true, total: #<BigDecimal:4d3a668,'0.0',9(36)>, tax: nil>
class ServicesController < ApplicationController
def new
setup
@service = @account.services.build
end
def create
@customer = Customer.find(params[:customer_id])
@account = @customer.accounts.find(params[:account_id])
@service = @account.services.create(service_params)
if @service.valid?
add_service_to_account(@account, @service)
@account.save
redirect_to customer_account_service_path(@customer, @account, @service)
else
render 'new'
end
end
end
class Service < ActiveRecord::Base
belongs_to :account
before_create :unset_paid
validates :cost, format: { allow_blank: true, with: /\A$?\d{1,4}(\.\d{0,2})?\Z/ }
def unset_paid
self.paid = false
end
end
这是视图错误:
ActionController::UrlGenerationError in ServicesController#create
No route matches {:account_id=>"31", :action=>"show", :controller=>"services", :customer_id=>"14", :id=>nil} missing required keys: [:id]
Extracted source (around line #21):
第 21 行
redirect_to customer_account_service_path(@customer, @account, @service)
相关路线:
new_customer_account_service GET /customers/:customer_id/accounts/:account_id/services/new(.:format) services#new
edit_customer_account_service GET /customers/:customer_id/accounts/:account_id/services/:id/edit(.:format) services#edit
customer_account_service GET /customers/:customer_id/accounts/:account_id/services/:id(.:format) services#show
PATCH /customers/:customer_id/accounts/:account_id/services/:id(.:format) services#update
PUT /customers/:customer_id/accounts/:account_id/services/:id(.:format) services#update
DELETE /customers/:customer_id/accounts/:account_id/services/:id(.:format) services#destroy
class CreateServices < ActiveRecord::Migration
def change
create_table :services do |t|
t.references :account, index: true, foreign_key: true
t.date :date
t.boolean :default_lawn_cost
t.decimal :cost
t.string :description
t.timestamps null: false
end
end
end
这就是我不喜欢 ActiveRecord 回调的部分原因;他们太聪明了,会制造一些奇怪的情况,让你对一些没有明确原因的错误感到不安。
如果before_create
或before_save
回调returnsfalse
,它将取消即将执行的数据库操作。 请参阅 this guide page 了解其工作原理。我猜这就是在这种情况下让您感到困惑的原因,因为一旦您尝试创建记录,就会调用 unset_paid
记录并意外取消整个 save/create 操作。反过来,这意味着新的未创建记录没有 id
,因此当您尝试重定向到记录的 URL 时,路径变为 /accounts/nil
.
最近在 Rails 世界流传着这样的建议,即您应该始终默认使用 save!
和 create!
,而不是它们的 un-banged 版本,因为前者会引发如果操作失败则报错。如果您使用了 @account.save!
,您会立即看到一个异常,将您指向问题的核心(即,在尝试保存记录时出现问题),而不是让您怀疑您的路线是否被施了魔法。
希望对您有所帮助!