I have added a "before_save" to my model to apply some logic to my model before saving. When I use this code, the record is created, then immediately updated (with the incorrect value). If I comment it out, there is no subsequent update when I create a new record.
我在模型中添加了一个“before_save”,以便在保存之前对模型应用一些逻辑。当我使用此代码时,将创建记录,然后立即更新(使用不正确的值)。如果我注释掉它,当我创建一个新记录时,没有后续更新。
Model
模型
class Transaction < ApplicationRecord
belongs_to :account
attr_accessor :trx_type
before_save do
if self.trx_type == "debit"
self.amount = self.amount * -1
end
end
end
Controller
控制器
class TransactionsController < ApplicationController
before_action :find_account
before_action :find_transaction, only: [:edit, :update, :show, :destroy]
# Index action to render all transactions
def index
@transactions = @account.transactions
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @transactions }
end
end
# New action for creating transaction
def new
@transaction = @account.transactions.build
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @transaction }
end
end
# Create action saves the trasaction into database
def create
@transaction = @account.transactions.create(transaction_params)
respond_to do |format|
if @transaction.save
format.html { redirect_to([@transaction.account, @transaction], :notice => 'Transaction was successfully created.') }
format.xml { render :xml => @transaction, :status => :created, :location => [@transaction.account, @transaction] }
else
format.html { render :action => "new" }
format.xml { render :xml => @transaction.errors, :status => :unprocessable_entity }
end
end
end
# Edit action retrieves the transaction and renders the edit page
def edit
end
# Update action updates the transaction with the new information
def update
respond_to do |format|
if @transaction.update_attributes(transaction_params)
format.html { redirect_to([@transaction.account, @transaction], :notice => 'Transaction was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @transaction.errors, :status => :unprocessable_entity }
end
end
end
# The show action renders the individual transaction after retrieving the the id
def show
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @transaction }
end
end
# The destroy action removes the transaction permanently from the database
def destroy
@transaction.destroy
respond_to do |format|
format.html { redirect_to(account_transactions_url) }
format.xml { head :ok }
end
end
private
def transaction_params
params.require(:transaction).permit(:trx_date, :description, :amount, :trx_type)
end
def find_account
@account = current_user.accounts.find(params[:account_id])
end
def find_transaction
@transaction = @account.transactions.find(params[:id])
end
end
Console Output
控制台输出
Started POST "/accounts/1/transactions" for 127.0.0.1 at 2018-03-20 13:59:37 -0400
Processing by TransactionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"kURRN8FaHmjrDU7y5cikBLREGZdMgHm4PsVUcOHxn7MAlqmi2zolA0LYOKQ46JkTzXl+Fkgj1O6SlBhVjdM5Qw==", "transaction"=>{"trx_type"=>"debit", "trx_date(1i)"=>"2018", "trx_date(2i)"=>"3", "trx_date(3i)"=>"20", "description"=>"Test 10", "amount"=>"132"}, "commit"=>"Create Transaction", "account_id"=>"1"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Account Load (0.5ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."user_id" = $1 AND "accounts"."id" = $2 LIMIT $3 [["user_id", 1], ["id", 1], ["LIMIT", 1]]
(0.2ms) BEGIN
SQL (0.6ms) INSERT INTO "transactions" ("trx_date", "description", "amount", "account_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["trx_date", "2018-03-20"], ["description", "Test 10"], ["amount", "-132.0"], ["account_id", 1], ["created_at", "2018-03-20 13:59:37.349781"], ["updated_at", "2018-03-20 13:59:37.349781"]]
(3.5ms) COMMIT
(0.1ms) BEGIN
SQL (0.3ms) UPDATE "transactions" SET "amount" = $1, "updated_at" = $2 WHERE "transactions"."id" = $3 [["amount", "132.0"], ["updated_at", "2018-03-20 13:59:37.355748"], ["id", 27]]
(0.9ms) COMMIT
Redirected to http://localhost:3000/accounts/1/transactions/27
Completed 302 Found in 16ms (ActiveRecord: 6.6ms)
I'm new with Rails and trying to understand what is happening with my code. I appreciate any help in advance.
我是Rails的新手,我试图理解我的代码发生了什么。我提前感谢任何帮助。
Thanks!
谢谢!
2 个解决方案
#1
3
There are two things here that are causing you some grief, but they're easy to address.
这里有两件事让你感到悲伤,但它们很容易处理。
First, in the create action of your controller you're actually calling two methods that persist data to the database, so that's why you're seeing two saves in the console output.
首先,在控制器的创建操作中,您实际上调用了两个将数据持久化到数据库的方法,因此您在控制台输出中看到了两个保存。
The first line in the method is responsible for the first save:
方法中的第一行负责第一次保存:
@transaction = @account.transactions.create(transaction_params)
@transaction = @account.transactions.create(transaction_params)
And this line here in your respond_to block is responsible for the second save:
respond_to block中的这一行负责第二次保存
if @transaction.save
如果@transaction.save
Second, the reason the record has the correct amount
in the first save and not in the second save is related to the logic in the before_save
callback of your Transaction model. It's taking the amount
and calling * -1
on it. Since the first save has already made the amount negative, the second save will flip it back to positive.
其次,记录在第一个保存中有正确的数量,而在第二个保存中没有正确的数量的原因与事务模型的before_save回调中的逻辑有关。它取钱,并调用* -1。由于第一个储蓄已经使金额为负数,第二个储蓄将把它转回正数。
#2
1
It seems like you need before_create
because it's unlikely you would change the type of transaction right?
似乎需要before_create因为不太可能会改变事务类型,对吧?
before_create do
if self.trx_type == "debit"
self.amount = self.amount * -1
end
end
Update: Looks like you need in your controller change:
更新:看起来您需要在您的控制器更改:
@transaction = @account.transactions.create(transaction_params)
to
来
@transaction = @account.transactions.build(transaction_params)
#1
3
There are two things here that are causing you some grief, but they're easy to address.
这里有两件事让你感到悲伤,但它们很容易处理。
First, in the create action of your controller you're actually calling two methods that persist data to the database, so that's why you're seeing two saves in the console output.
首先,在控制器的创建操作中,您实际上调用了两个将数据持久化到数据库的方法,因此您在控制台输出中看到了两个保存。
The first line in the method is responsible for the first save:
方法中的第一行负责第一次保存:
@transaction = @account.transactions.create(transaction_params)
@transaction = @account.transactions.create(transaction_params)
And this line here in your respond_to block is responsible for the second save:
respond_to block中的这一行负责第二次保存
if @transaction.save
如果@transaction.save
Second, the reason the record has the correct amount
in the first save and not in the second save is related to the logic in the before_save
callback of your Transaction model. It's taking the amount
and calling * -1
on it. Since the first save has already made the amount negative, the second save will flip it back to positive.
其次,记录在第一个保存中有正确的数量,而在第二个保存中没有正确的数量的原因与事务模型的before_save回调中的逻辑有关。它取钱,并调用* -1。由于第一个储蓄已经使金额为负数,第二个储蓄将把它转回正数。
#2
1
It seems like you need before_create
because it's unlikely you would change the type of transaction right?
似乎需要before_create因为不太可能会改变事务类型,对吧?
before_create do
if self.trx_type == "debit"
self.amount = self.amount * -1
end
end
Update: Looks like you need in your controller change:
更新:看起来您需要在您的控制器更改:
@transaction = @account.transactions.create(transaction_params)
to
来
@transaction = @account.transactions.build(transaction_params)