Ruby on rails 更新嵌套属性时出现问题
我正在尝试使用Rails 4.1构建一个小型费用跟踪应用程序。当用户提交费用申请时,其状态默认标记为挂起。管理员必须批准该请求。我用状态机gem来做这个 使用嵌套表单从费用显示页面添加注释,如下所示:Ruby on rails 更新嵌套属性时出现问题,ruby-on-rails,Ruby On Rails,我正在尝试使用Rails 4.1构建一个小型费用跟踪应用程序。当用户提交费用申请时,其状态默认标记为挂起。管理员必须批准该请求。我用状态机gem来做这个 使用嵌套表单从费用显示页面添加注释,如下所示: <%= nested_form_for (@expense) do |f| %> <div class="form-group"> <%= f.label :state %><br /> <%= f.
<%= nested_form_for (@expense) do |f| %>
<div class="form-group">
<%= f.label :state %><br />
<%= f.collection_select :state, @expense.state_transitions, :event, :human_to_name, :include_blank => @expense.human_state_name, class: "form-control" %>
</div>
<%= f.fields_for :comments, @expense.comments.build do |comment| %>
<div class="form-group">
<%= comment.label :comment%>
<%= comment.text_area :comment, class: "form-control" %>
</div>
<% end %>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
带有状态机的费用模型如下所示:
class ExpensesController < ApplicationController
def new
@expense = Expense.new
@item = @expense.items.build
@comment = @expense.comments.build
end
def show
@expense = Expense.find(params[:id])
@items = Item.where(:expense_id => @expense.id)
end
def update
@expense = Expense.find(params[:id])
if @expense.update(expense_params)
if @expense.state == "approved"
ExpenseMailer.expense_approved(@expense).deliver
flash[:notice] = "Expense Report Updated"
redirect_to expenses_path
elsif @expense.state = "rejected"
ExpenseMailer.expense_declined(@expense).deliver
flash[:notice] = "Expense Report Updated"
redirect_to expenses_path
end
else
render 'edit'
end
end
private
def expense_params
params.require(:expense).permit(:claim, :department_id, :expense_type_id, :expense_attachment, :state, :notes, items_attributes: [:id, :description, :amount, :issue_date, :_destroy], comments_attributes:[:id, :comment, :expense_id])
end
state_machine initial: :pending do
state :pending
state :approved
state :rejected
event :approved do
transition [:pending, :rejected] => :approved
end
event :rejected do
transition [:pending, :approved] => :rejected
end
end
我猜我在构建注释属性时犯了一些错误。有人能告诉我在哪里需要修改吗
拒绝的记录器信息:
Started GET "/expenses/17" for 127.0.0.1 at 2014-08-15 16:22:43 +0530
Processing by ExpensesController#show as HTML
Parameters: {"id"=>"17"}
[1m[35mExpense Load (0.2ms)[0m SELECT "expenses".* FROM "expenses" WHERE "expenses"."id" = ? LIMIT 1 [["id", 17]]
[1m[36mItem Load (0.1ms)[0m [1mSELECT "items".* FROM "items" WHERE "items"."expense_id" = ?[0m [["expense_id", 17]]
[1m[35mComment Load (0.2ms)[0m SELECT "comments".* FROM "comments" WHERE "comments"."expense_id" = ? [["expense_id", 17]]
Rendered expenses/show.html.erb within layouts/application (16.2ms)
Completed 200 OK in 45ms (Views: 42.8ms | ActiveRecord: 0.5ms)
Started PATCH "/expenses/17" for 127.0.0.1 at 2014-08-15 16:22:53 +0530
Processing by ExpensesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"MAEL2UYzos76NV6/eumHkXcpR2ge09wm6eOGQ+eEGCA=", "expense"=>{"state"=>"rejected", "comments_attributes"=>{"0"=>{"comment"=>"checking logger for rejected!"}}}, "commit"=>"Submit", "id"=>"17"}
[1m[36mExpense Load (0.2ms)[0m [1mSELECT "expenses".* FROM "expenses" WHERE "expenses"."id" = ? LIMIT 1[0m [["id", 17]]
[1m[35m (0.1ms)[0m begin transaction
[1m[36mSQL (8.1ms)[0m [1mUPDATE "expenses" SET "state" = ?, "updated_at" = ? WHERE "expenses"."id" = 17[0m [["state", "rejected"], ["updated_at", "2014-08-15 10:52:53.030676"]]
[1m[35mSQL (0.2ms)[0m INSERT INTO "comments" ("comment", "created_at", "expense_id", "updated_at") VALUES (?, ?, ?, ?) [["comment", "checking logger for rejected!"], ["created_at", "2014-08-15 10:52:53.040889"], ["expense_id", 17], ["updated_at", "2014-08-15 10:52:53.040889"]]
[1m[36m (4.2ms)[0m [1mcommit transaction[0m
Redirected to http://localhost:3000/expenses
Completed 302 Found in 24ms (ActiveRecord: 12.8ms)
Started GET "/expenses/16" for 127.0.0.1 at 2014-08-15 16:22:30 +0530
Processing by ExpensesController#show as HTML
Parameters: {"id"=>"16"}
[1m[35mExpense Load (0.3ms)[0m SELECT "expenses".* FROM "expenses" WHERE "expenses"."id" = ? LIMIT 1 [["id", 16]]
[1m[36mItem Load (0.2ms)[0m [1mSELECT "items".* FROM "items" WHERE "items"."expense_id" = ?[0m [["expense_id", 16]]
[1m[35mComment Load (0.3ms)[0m SELECT "comments".* FROM "comments" WHERE "comments"."expense_id" = ? [["expense_id", 16]]
Rendered expenses/show.html.erb within layouts/application (167.3ms)
Completed 200 OK in 244ms (Views: 213.7ms | ActiveRecord: 1.1ms)
Started PATCH "/expenses/16" for 127.0.0.1 at 2014-08-15 16:22:41 +0530
Processing by ExpensesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"MAEL2UYzos76NV6/eumHkXcpR2ge09wm6eOGQ+eEGCA=", "expense"=>{"state"=>"approved", "comments_attributes"=>{"0"=>{"comment"=>"checking logger!"}}}, "commit"=>"Submit", "id"=>"16"}
[1m[36mExpense Load (0.2ms)[0m [1mSELECT "expenses".* FROM "expenses" WHERE "expenses"."id" = ? LIMIT 1[0m [["id", 16]]
[1m[35m (0.1ms)[0m begin transaction
[1m[36mSQL (0.5ms)[0m [1mUPDATE "expenses" SET "state" = ?, "updated_at" = ? WHERE "expenses"."id" = 16[0m [["state", "approved"], ["updated_at", "2014-08-15 10:52:41.604580"]]
[1m[35mSQL (0.5ms)[0m INSERT INTO "comments" ("comment", "created_at", "expense_id", "updated_at") VALUES (?, ?, ?, ?) [["comment", "checking logger!"], ["created_at", "2014-08-15 10:52:41.607555"], ["expense_id", 16], ["updated_at", "2014-08-15 10:52:41.607555"]]
[1m[36m (4.0ms)[0m [1mcommit transaction[0m
Redirected to http://localhost:3000/expenses
Completed 302 Found in 17ms (ActiveRecord: 5.3ms)
用于批准的记录器信息:
Started GET "/expenses/17" for 127.0.0.1 at 2014-08-15 16:22:43 +0530
Processing by ExpensesController#show as HTML
Parameters: {"id"=>"17"}
[1m[35mExpense Load (0.2ms)[0m SELECT "expenses".* FROM "expenses" WHERE "expenses"."id" = ? LIMIT 1 [["id", 17]]
[1m[36mItem Load (0.1ms)[0m [1mSELECT "items".* FROM "items" WHERE "items"."expense_id" = ?[0m [["expense_id", 17]]
[1m[35mComment Load (0.2ms)[0m SELECT "comments".* FROM "comments" WHERE "comments"."expense_id" = ? [["expense_id", 17]]
Rendered expenses/show.html.erb within layouts/application (16.2ms)
Completed 200 OK in 45ms (Views: 42.8ms | ActiveRecord: 0.5ms)
Started PATCH "/expenses/17" for 127.0.0.1 at 2014-08-15 16:22:53 +0530
Processing by ExpensesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"MAEL2UYzos76NV6/eumHkXcpR2ge09wm6eOGQ+eEGCA=", "expense"=>{"state"=>"rejected", "comments_attributes"=>{"0"=>{"comment"=>"checking logger for rejected!"}}}, "commit"=>"Submit", "id"=>"17"}
[1m[36mExpense Load (0.2ms)[0m [1mSELECT "expenses".* FROM "expenses" WHERE "expenses"."id" = ? LIMIT 1[0m [["id", 17]]
[1m[35m (0.1ms)[0m begin transaction
[1m[36mSQL (8.1ms)[0m [1mUPDATE "expenses" SET "state" = ?, "updated_at" = ? WHERE "expenses"."id" = 17[0m [["state", "rejected"], ["updated_at", "2014-08-15 10:52:53.030676"]]
[1m[35mSQL (0.2ms)[0m INSERT INTO "comments" ("comment", "created_at", "expense_id", "updated_at") VALUES (?, ?, ?, ?) [["comment", "checking logger for rejected!"], ["created_at", "2014-08-15 10:52:53.040889"], ["expense_id", 17], ["updated_at", "2014-08-15 10:52:53.040889"]]
[1m[36m (4.2ms)[0m [1mcommit transaction[0m
Redirected to http://localhost:3000/expenses
Completed 302 Found in 24ms (ActiveRecord: 12.8ms)
Started GET "/expenses/16" for 127.0.0.1 at 2014-08-15 16:22:30 +0530
Processing by ExpensesController#show as HTML
Parameters: {"id"=>"16"}
[1m[35mExpense Load (0.3ms)[0m SELECT "expenses".* FROM "expenses" WHERE "expenses"."id" = ? LIMIT 1 [["id", 16]]
[1m[36mItem Load (0.2ms)[0m [1mSELECT "items".* FROM "items" WHERE "items"."expense_id" = ?[0m [["expense_id", 16]]
[1m[35mComment Load (0.3ms)[0m SELECT "comments".* FROM "comments" WHERE "comments"."expense_id" = ? [["expense_id", 16]]
Rendered expenses/show.html.erb within layouts/application (167.3ms)
Completed 200 OK in 244ms (Views: 213.7ms | ActiveRecord: 1.1ms)
Started PATCH "/expenses/16" for 127.0.0.1 at 2014-08-15 16:22:41 +0530
Processing by ExpensesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"MAEL2UYzos76NV6/eumHkXcpR2ge09wm6eOGQ+eEGCA=", "expense"=>{"state"=>"approved", "comments_attributes"=>{"0"=>{"comment"=>"checking logger!"}}}, "commit"=>"Submit", "id"=>"16"}
[1m[36mExpense Load (0.2ms)[0m [1mSELECT "expenses".* FROM "expenses" WHERE "expenses"."id" = ? LIMIT 1[0m [["id", 16]]
[1m[35m (0.1ms)[0m begin transaction
[1m[36mSQL (0.5ms)[0m [1mUPDATE "expenses" SET "state" = ?, "updated_at" = ? WHERE "expenses"."id" = 16[0m [["state", "approved"], ["updated_at", "2014-08-15 10:52:41.604580"]]
[1m[35mSQL (0.5ms)[0m INSERT INTO "comments" ("comment", "created_at", "expense_id", "updated_at") VALUES (?, ?, ?, ?) [["comment", "checking logger!"], ["created_at", "2014-08-15 10:52:41.607555"], ["expense_id", 16], ["updated_at", "2014-08-15 10:52:41.607555"]]
[1m[36m (4.0ms)[0m [1mcommit transaction[0m
Redirected to http://localhost:3000/expenses
Completed 302 Found in 17ms (ActiveRecord: 5.3ms)
我不知道你为什么会出错,但我会给你一些关于/gems的想法
--
状态机
由于Rails是,您必须了解这些GEM是如何工作的——它们是建立“状态机”(用于预测电路中的有限“状态”)的电子学方法的外推:
我试图用它来演示的是,通过在应用程序中包含状态机
,实际上是在指示对象的状态(它不是而只是另一个属性)
目前,您正在将注释
模型的状态
属性视为一个属性,而该属性本身可以被视为一个对象
--
对象
请注意状态机repo中的此功能:
注意这与state属性无关吗
我认为你最好按照它的本来面目来对待状态
方法-一种影响状态机
本身的方法。我会通过几种方式来实现这一点:
#app/controllers/expenses_controller.rb
Class ExpensesController < ApplicationController
def new
@expense = Expense.build
end
def edit
@expense = Expense.build params[:id]
end
end
#app/models/expense.rb
Class Expense < ActiveRecord::Base
state_machine :state, :initial => :pending do
state :pending
state :approved
state :rejected
event :approve do
transition [:pending, :rejected] => :approved
end
event :reject do
transition [:pending, :approved] => :rejected
end
after_transition :on => :approved, :do => :send_approval_email
after_transition :on => :rejected, :do => :send_rejection_email
def send_approval_email
ExpenseMailer.expense_approved(self).deliver #-> might need to call outide of state_machine block
end
def send_rejection_email
ExpenseMailer.expense_declined(self).deliver
end
end
end
#app/controllers/expenses_controller.rb
Class ExpensesController < ApplicationController
def update
@expense = Expense.find params[:id]
if @expense.update(expense_params)
flash[:notice] = "Expense Report Updated"
redirect_to expenses_path
end
end
end
这将使您能够执行以下操作:
#app/controllers/expenses_controller.rb
Class ExpensesController < ApplicationController
def new
@expense = Expense.build
end
def edit
@expense = Expense.build params[:id]
end
end
#app/models/expense.rb
Class Expense < ActiveRecord::Base
state_machine :state, :initial => :pending do
state :pending
state :approved
state :rejected
event :approve do
transition [:pending, :rejected] => :approved
end
event :reject do
transition [:pending, :approved] => :rejected
end
after_transition :on => :approved, :do => :send_approval_email
after_transition :on => :rejected, :do => :send_rejection_email
def send_approval_email
ExpenseMailer.expense_approved(self).deliver #-> might need to call outide of state_machine block
end
def send_rejection_email
ExpenseMailer.expense_declined(self).deliver
end
end
end
#app/controllers/expenses_controller.rb
Class ExpensesController < ApplicationController
def update
@expense = Expense.find params[:id]
if @expense.update(expense_params)
flash[:notice] = "Expense Report Updated"
redirect_to expenses_path
end
end
end
#app/controllers/expenses_controller.rb
类别费用控制器<应用程序控制器
def更新
@费用=费用。查找参数[:id]
如果@expense.update(费用参数)
flash[:通知]=“费用报告已更新”
将\u重定向到\u路径
结束
结束
结束
顺便说一句,您需要更改“事件”以使“状态”具有不同的名称。根据我上面提到的面向对象的参考资料,您需要能够调用类似的
@object.approve
等我已尝试重新缩进您的代码,请检查其correct@mu無 是的,没错。非常感谢。顺便说一句,state\u机器
的维护不如aasm\u状态
——工作方式非常相似,只是后者更新更为频繁。在强参数方法中,你的状态
属性在哪里?@RichPeck我使用的是一个积极维护的状态机器叉。state属性位于强参数中。“这是名单上的第五个。”里克·佩克谢谢你的精彩回答。我已经接受了您建议的控制器方法,我将花一些时间详细了解您关于状态机的建议。模型中的state属性是:state。根据您的建议,我在只提交评论而不更改状态时查看了参数,state的值为空。如何使其保持原始状态?根据参数为您更新答案。提交时,您的状态
属性似乎为空。注释现在已保存。但是,在设置默认值后,“状态”下拉列表现在只显示下拉列表中的一个值。例如,如果以前的状态最初是“已批准”,则显示页面中的下拉列表显示“已拒绝”,反之亦然。我使用了模型方法,电子邮件不会发送。事实上,我已经尝试过类似的东西,但几天前无法让它工作,并在这里提出了一个问题。所以,我尝试了所有流行的状态机——SM、assm、transition、workflow等等。没有一个模型方法被触发。所以,我把它们都扔掉了。将当前_状态添加到费用表并开始保存状态值。编写了一个条件循环,检查state==当前状态,在这种情况下不会发送电子邮件。非常感谢你的努力。你花了将近半天的时间帮我弄明白了。非常感谢!