在我的rails 4.1 app中使用devise进行用户身份验证。
我尝试从名为transactions_controller
的控制器手动创建用户,并且有一个名为CreateAdminService
的类,用于根据user
中收到的参数创建POST
这是CreateAdminService
中执行该操作的代码
def call (params, confirm = true, role = :user)
user = User.find_or_create_by!(email: params[:email]) do |user|
user.name = params[:name] if params[:name]
user.password = params[:password]
user.password_confirmation = params[:password_confirmation]
user.confirm! if confirm
user.send("#{role}!") unless role == :user
end
end
一切正常。当我发送的密码不匹配时,将显示验证失败消息,但会创建记录。新记录没有存储任何密码。我不知道这是devise
或find_or_create_by!
显示此行为的问题。
我尝试在没有find_or_create_by
的情况下使用!
,这会创建记录并且不会检查任何验证或抛出任何非常糟糕的错误。
有人可以帮助调试这种情况发生的原因,或者我可以在所有验证工作的同时创建用户。
编辑:用户模型如下
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
enum role: [:user, :vip, :admin]
enum status: [:active, :suspended]
has_many :accounts
has_many :txns
after_initialize :set_default_role, :if => :new_record?
after_create :setup_account
private
def set_default_role
self.role ||= :user
self.status ||= :active
end
def setup_account
self.accounts.create!
end
end
请求和错误的日志是
Started POST "/start" for 127.0.0.1 at 2014-06-01 22:08:38 +0400
Processing by TransactionsController#start as JSON
Parameters: {"user"=>{"name"=>"test", "email"=>"yavaidya4@test.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "transaction"=>{"user"=>{"name"=>"test", "email"=>"yavaidya4@test.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."email" = 'yavaidya4@test.com' LIMIT 1
(0.1ms) begin transaction
Binary data inserted for `string` type on column `encrypted_password`
SQL (0.4ms) INSERT INTO "users" ("confirmed_at", "created_at", "email", "encrypted_password", "name", "role", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?) [["confirmed_at", "2014-06-01 18:08:38.344688"], ["created_at", "2014-06-01 18:08:38.345141"], ["email", "yavaidya4@test.com"], ["encrypted_password", "$2a$10$nUiH/dLDrcNAOWpAPTBBYO.pA/mKKpHoCNPiM/0oX/jBiZy8cogWC"], ["name", "test"], ["role", 0], ["status", 0], ["updated_at", "2014-06-01 18:08:38.345141"]]
Account Exists (0.2ms) SELECT 1 AS one FROM "accounts" WHERE "accounts"."user_id" = 14 LIMIT 1
SQL (0.2ms) INSERT INTO "accounts" ("balance", "created_at", "number", "status", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?) [["balance", 0.0], ["created_at", "2014-06-01 18:08:38.364984"], ["number", "22743176"], ["status", 1], ["updated_at", "2014-06-01 18:08:38.364984"], ["user_id", 14]]
(0.7ms) commit transaction
(0.0ms) begin transaction
(0.2ms) rollback transaction
Completed 422 Unprocessable Entity in 107ms
ActiveRecord::RecordInvalid - Validation failed: Password confirmation doesn't match Password:
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/validations.rb:57:in `save!'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/attribute_methods/dirty.rb:29:in `save!'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/transactions.rb:273:in `block in save!'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/transactions.rb:329:in `block in with_transaction_returning_status'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `block in transaction'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/connection_adapters/abstract/database_statements.rb:219:in `within_new_transaction'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `transaction'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/transactions.rb:208:in `transaction'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/transactions.rb:326:in `with_transaction_returning_status'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/transactions.rb:273:in `save!'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/validations.rb:41:in `create!'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/relation.rb:140:in `block in create!'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/relation.rb:286:in `scoping'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/relation.rb:140:in `create!'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/relation.rb:208:in `find_or_create_by!'
() Users/test/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.1.0/lib/active_record/querying.rb:6:in `find_or_create_by!'
app/services/create_admin_service.rb:11:in `call'
app/controllers/transactions_controller.rb:8:in `start'
答案 0 :(得分:2)
好的,你的日志记录看起来很奇怪:它明显地保存了用户,并且只有在那之后验证才会失败。还有一些奇怪的事情:confirmed_at
晚于created_at/updated_at
。等待。 confirmed_at
已经填写了?在您的创建块中,您可以在用户上混合创建和操作。
我只是在猜测,但在我看来,confirm!
可能以某种方式迫使用户被保存,然后在find_or_create_by
结束时再次保存用户(或{}尝试保存),然后检查验证。
检查devise code我的预感已经确认(双关语!):它会在没有任何验证的情况下保存用户。
所以我会尝试以下方法:
def call (params, confirm = true, role = :user)
user = User.find_or_create_by!(email: params[:email]) do |user|
user.name = params[:name] if params[:name]
user.password = params[:password]
user.password_confirmation = params[:password_confirmation]
end
user.confirm! if confirm
user.send("#{role}!") unless role == :user
end
如果未创建用户,则抛出异常,并且最后两行永远不会执行。
旁注:after_initialize
并不理想,因为它被称为很多。
在你的情况下,因为你似乎只是想设置一些默认值,我会做一个
before_create :set_default_role
这只会在保存新用户之前调用。
答案 1 :(得分:0)
也许开始使用带有参数的find_or_initialize_by
,然后调用这样的条件:
def call (params, confirm = true, role = :user)
user = User.find_or_initialize_by(email: params[:email], name: params[:name])
user.password = params[:password]
user.password_confirmation = params[:password_confirmation]
if user.save
user.confirm! if confirm
user.send(role) unless roll == :user
end
end