NoMethodError - #<ActionDispatch:: 的未定义方法“email”
NoMethodError - undefined method `email' for #<ActionDispatch::
设计 3.5.2,Rails4.2.3
登录时,我试图传递隐藏的 role_id 和 email/password 组合。我允许同一封电子邮件在不同的子域上再次注册,这会导致传递不同的 role_id。 email+role_id是用户的唯一索引。
我可以创建用户,但无法登录。当我提交登录表单时,遇到以下错误:
undefined method 'email' for #<ActionDispatch::Request:0x007fa21628bda0>
编辑:
如果有人能解释将电子邮件唯一性验证更改为电子邮件+role_id(不是either/or,而是和)的过程,这就是我需要完成的。正确遵循该过程可能会避免此错误。
调试信息:
POST参数如下:
{"utf8"=>"✓",
"authenticity_token"=>"[FILTERED]",
"member"=>{"role_id"=>"1",
"email"=>"some.user@email.com",
"password"=>"[FILTERED]",
"remember_me"=>"0"},
"commit"=>"Log in"}
这是我的会员模型:
class Member < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :timeoutable, :omniauthable
belongs_to :role
def self.find_for_authentication(warden_conditions)
where(:email => warden_conditions[:email], :role_id => warden_conditions[:role_id]).first
end
end
在config/initializers/devise.rb中设置如下:
config.authentication_keys = [:email, :role_id]
config.request_keys = [:email, :role_id]
我的 views/devise/sessions/new.html.erb 包括:
<%= f.hidden_field :role_id, :value => Role.find_by_name(current_subdomain).id %>
我调整了 vendor/bundle/ruby/1.9.1/gems/devise-3.5.2/lib/devise/models/validatable.rb 通过更改此行:
validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
至:
validates_uniqueness_of :email, :scope => :role_id, allow_blank: true, if: :email_changed? #using subdomains for validation
成员的相关数据库迁移可在此处找到:
...devise_create_members.rb
class DeviseCreateMembers < ActiveRecord::Migration
def change
create_table(:members) do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
t.string :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
t.string :unlock_token # Only if unlock strategy is :email or :both
t.datetime :locked_at
t.timestamps null: false
end
add_index :members, :email, unique: true
add_index :members, :reset_password_token, unique: true
add_index :members, :confirmation_token, unique: true
add_index :members, :unlock_token, unique: true
end
...add_columns_to_member.rb
class AddColumnsToMember < ActiveRecord::Migration
def change
add_reference :members, :contact, index: true
add_reference :members, :role, index: true
add_reference :members, :ownership, index: true
add_column :members, :account_status, :string
end
end
...reindex_members_email_and_role.rb
class ReindexMembersEmailAndRole < ActiveRecord::Migration
def change
add_index :members, [:email, :role_id], :unique => true
end
end
跟踪中的最后一项是:
vendor/bundle/ruby/1.9.1/gems/devise-3.5.2/lib/devise/strategies/authenticatable.rb:152:在request_values'[=71=中的`块中]
keys = request_keys.respond_to?(:keys) ? request_keys.keys : request_keys
values = keys.map { |k| self.request.send(k) } <--ERROR THIS LINE
Hash[keys.zip(values)]
end
我错过了什么?
为了解决这个问题,我更改了 config/initializers/devise.rb
以反映以下内容:
config.request_keys = { role_id: false }
这解决了问题,但仍然阻止了同一封电子邮件使用不同的角色 ID 进行注册。为了解决这个问题,我从我的用户模型中删除了 :validatable
并添加了:
validates_uniqueness_of :email, :case_sensitive => false, :scope => :role_id, :allow_blank => true, :if => :email_changed?
validates_format_of :email, :with => Devise.email_regexp, :allow_blank => true, :if => :email_changed?
validates_presence_of :password, :on=>:create
validates_confirmation_of :password, :on=>:create
validates_length_of :password, :within => Devise.password_length, :allow_blank => true
这允许相同的电子邮件地址使用不同的 role_id 进行注册。
我还在 authenticatable.rb 中更改了以下内容:
def request_values
keys = request_keys.respond_to?(:keys) ? request_keys.keys : request_keys
values = keys.map { |k| self.request[self.scope][k] }
# values = keys.map { |k| self.request.send(k) }
Hash[keys.zip(values)]
end
更新
我厌倦了总是不得不重新破解设计库,尤其是在我更新了 gems 或转移了应用程序之后。我发现此页面提供了更好的解决方法(仍然按照上面列出的有关验证用户模型的步骤):
(来自 https://github.com/plataformatec/devise/pull/3965)
注释掉我们在上面编辑的以下行:
# config.request_keys = { role_id: false }
按如下方式编辑 config.authentication_keys
行:
config.authentication_keys = { email: true, role_id: false }
问题是 request_keys
仅支持预定义键,例如 :subdomain
。
现在应该可以创建自定义密钥组合来进行身份验证了。
设计 3.5.2,Rails4.2.3
登录时,我试图传递隐藏的 role_id 和 email/password 组合。我允许同一封电子邮件在不同的子域上再次注册,这会导致传递不同的 role_id。 email+role_id是用户的唯一索引。
我可以创建用户,但无法登录。当我提交登录表单时,遇到以下错误:
undefined method 'email' for #<ActionDispatch::Request:0x007fa21628bda0>
编辑:
如果有人能解释将电子邮件唯一性验证更改为电子邮件+role_id(不是either/or,而是和)的过程,这就是我需要完成的。正确遵循该过程可能会避免此错误。
调试信息:
POST参数如下:
{"utf8"=>"✓",
"authenticity_token"=>"[FILTERED]",
"member"=>{"role_id"=>"1",
"email"=>"some.user@email.com",
"password"=>"[FILTERED]",
"remember_me"=>"0"},
"commit"=>"Log in"}
这是我的会员模型:
class Member < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :timeoutable, :omniauthable
belongs_to :role
def self.find_for_authentication(warden_conditions)
where(:email => warden_conditions[:email], :role_id => warden_conditions[:role_id]).first
end
end
在config/initializers/devise.rb中设置如下:
config.authentication_keys = [:email, :role_id]
config.request_keys = [:email, :role_id]
我的 views/devise/sessions/new.html.erb 包括:
<%= f.hidden_field :role_id, :value => Role.find_by_name(current_subdomain).id %>
我调整了 vendor/bundle/ruby/1.9.1/gems/devise-3.5.2/lib/devise/models/validatable.rb 通过更改此行:
validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
至:
validates_uniqueness_of :email, :scope => :role_id, allow_blank: true, if: :email_changed? #using subdomains for validation
成员的相关数据库迁移可在此处找到:
...devise_create_members.rb
class DeviseCreateMembers < ActiveRecord::Migration
def change
create_table(:members) do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
t.string :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
t.string :unlock_token # Only if unlock strategy is :email or :both
t.datetime :locked_at
t.timestamps null: false
end
add_index :members, :email, unique: true
add_index :members, :reset_password_token, unique: true
add_index :members, :confirmation_token, unique: true
add_index :members, :unlock_token, unique: true
end
...add_columns_to_member.rb
class AddColumnsToMember < ActiveRecord::Migration
def change
add_reference :members, :contact, index: true
add_reference :members, :role, index: true
add_reference :members, :ownership, index: true
add_column :members, :account_status, :string
end
end
...reindex_members_email_and_role.rb
class ReindexMembersEmailAndRole < ActiveRecord::Migration
def change
add_index :members, [:email, :role_id], :unique => true
end
end
跟踪中的最后一项是:
vendor/bundle/ruby/1.9.1/gems/devise-3.5.2/lib/devise/strategies/authenticatable.rb:152:在request_values'[=71=中的`块中]
keys = request_keys.respond_to?(:keys) ? request_keys.keys : request_keys
values = keys.map { |k| self.request.send(k) } <--ERROR THIS LINE
Hash[keys.zip(values)]
end
我错过了什么?
为了解决这个问题,我更改了 config/initializers/devise.rb
以反映以下内容:
config.request_keys = { role_id: false }
这解决了问题,但仍然阻止了同一封电子邮件使用不同的角色 ID 进行注册。为了解决这个问题,我从我的用户模型中删除了 :validatable
并添加了:
validates_uniqueness_of :email, :case_sensitive => false, :scope => :role_id, :allow_blank => true, :if => :email_changed?
validates_format_of :email, :with => Devise.email_regexp, :allow_blank => true, :if => :email_changed?
validates_presence_of :password, :on=>:create
validates_confirmation_of :password, :on=>:create
validates_length_of :password, :within => Devise.password_length, :allow_blank => true
这允许相同的电子邮件地址使用不同的 role_id 进行注册。
我还在 authenticatable.rb 中更改了以下内容:
def request_values
keys = request_keys.respond_to?(:keys) ? request_keys.keys : request_keys
values = keys.map { |k| self.request[self.scope][k] }
# values = keys.map { |k| self.request.send(k) }
Hash[keys.zip(values)]
end
更新
我厌倦了总是不得不重新破解设计库,尤其是在我更新了 gems 或转移了应用程序之后。我发现此页面提供了更好的解决方法(仍然按照上面列出的有关验证用户模型的步骤):
(来自 https://github.com/plataformatec/devise/pull/3965)
注释掉我们在上面编辑的以下行:
# config.request_keys = { role_id: false }
按如下方式编辑 config.authentication_keys
行:
config.authentication_keys = { email: true, role_id: false }
问题是 request_keys
仅支持预定义键,例如 :subdomain
。
现在应该可以创建自定义密钥组合来进行身份验证了。