Rails 设计不会将额外的输入字段保存到数据库
Rails devise doesn't save extra input fields to database
我在使用 Devise gem 将额外的用户字段值插入数据库时遇到问题。我缺少什么?
我正在使用
ruby 2.1.5p273
Rails 4.1.8
这是我的user.rb模型
class User < ActiveRecord::Base
belongs_to :country
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :authentication_keys => [:login]
attr_accessor :login, :name, :last_name, :address, :post_number, :city, :mobile
validates :username, presence: true, length: {maximum: 25}, :uniqueness => { :case_sensitive => false }
validates :name, presence:true
validates :last_name, presence:true
validates :address, presence:true
validates :post_number, presence:true
validates :city, presence:true
validates :country, presence:true
validates :mobile, presence:true
def login=(login)
@login = login
end
def login
@login || self.username || self.email
end
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(conditions).where(["username = :value OR lower(email) = lower(:value)", { :value => login }]).first
else
where(conditions).first
end
end
end
我的应用控制器
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username << :email << :password << :password_confirmation << :remember_me << :name << :last_name << :address << :post_number << :city << :country_id << :mobile
devise_parameter_sanitizer.for(:sign_in) << :login << :username << :email << :password << :remember_me
devise_parameter_sanitizer.for(:account_update) << :username << :email << :password << :password_confirmation << :current_password << :name << :last_name << :address << :post_number << :city << :country_id << :mobile
end
end
应用程序控制器(V2,我试过船路)
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me, :name, :last_name, :address, :post_number, :city, :country_id, :mobile) }
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :username, :email, :password, :remember_me) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :email, :password, :password_confirmation, :current_password, :name, :last_name, :address, :post_number, :city, :country_id, :mobile) }
end
end
Registratiions/new.html.erb
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :username %><br />
<%= f.text_field :username, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if @validatable %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<hr>
<div>
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div>
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
</div>
<div>
<%= f.label :address %><br />
<%= f.text_field :address %>
</div>
<div>
<%= f.label :post_number %><br />
<%= f.text_field :post_number %>
</div>
<div>
<%= f.label :city %><br />
<%= f.text_field :city %>
</div>
<div>
<%= f.label :country_id %><br />
<%= f.select(:country_id, options_from_collection_for_select(Country.all, :id, :name)) %>
</div>
<div>
<%= f.label :mobile %><br />
<%= f.text_field :mobile %>
</div>
<br><br>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
这是我提交表单时发生的事情的日志
Started POST "/users" for 127.0.0.1 at 2015-01-12 21:29:36 +0100
Processing by RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"YXPl+X5Xpib9yG4ywUY2BAOmiGdNUtkQZtIgxqBXbak=", "user"=>{"email"=>"test@gmail.com", "username"=>"testUser", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "name"=>"Test", "last_name"=>"Test", "address"=>"Test", "post_number"=>"21332", "city"=>"TestCity", "country_id"=>"81831761", "mobile"=>"333666333666"}, "commit"=>"Sign up"}
(0.1ms) begin transaction
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'test@gmail.com' LIMIT 1
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."username") = LOWER('testUser') LIMIT 1
Country Load (0.0ms) SELECT "countries".* FROM "countries" WHERE "countries"."id" = ? LIMIT 1 [["id", 81831761]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = '0ddbdfeadb0c6758be3dda41b068fd319e0fd63cefcb16c5b985f90ab16e6784' ORDER BY "users"."id" ASC LIMIT 1
Binary data inserted for `string` type on column `confirmation_token`
Binary data inserted for `string` type on column `encrypted_password`
SQL (0.3ms) INSERT INTO "users" ("confirmation_sent_at", "confirmation_token", "country_id", "created_at", "email", "encrypted_password", "updated_at", "username") VALUES (?, ?, ?, ?, ?, ?, ?, ?) [["confirmation_sent_at", "2015-01-12 20:29:36.962365"], ["confirmation_token", "0ddbdfeadb0c6758be3dda41b068fd319e0fd63cefcb16c5b985f90ab16e6784"], ["country_id", 81831761], ["created_at", "2015-01-12 20:29:36.742990"], ["email", "test@gmail.com"], ["encrypted_password", "a$bL6dOOVGzfJ5eOGA8mU/ces7w1CCjJk8Z8rlj6BvSQyqbLgazqrVW"], ["updated_at", "2015-01-12 20:29:36.742990"], ["username", "testUser"]]
Rendered devise/mailer/confirmation_instructions.html.erb (0.8ms)
我有两个问题:
- 我必须做什么,所以设计将扩展他的 INSERT sql 查询以插入额外的数据库字段值?
- 应用控制器devise_parameter_sanitizer哪种写法是正确的?
谢谢帮助
我找到了解决办法!
在 rails 4 中,您必须在 controller
中指定 user_params
这是我的users_controller(添加user_params)
class UsersController < ApplicationController
def index
@users = User.all
end
def new
@user = User.new
end
private
def user_params
params.require(:user).permit(:username, :email, :password, :password_confirmation, :remember_me, :name, :last_name, :address, :post_number, :city, :country_id, :mobile)
end
end
这是我的用户模型(已删除attr_accessor)
class User < ActiveRecord::Base
belongs_to :country
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :authentication_keys => [:login]
validates :username, presence: true, length: {maximum: 25}, :uniqueness => { :case_sensitive => false }
validates :name, presence:true, length: {maximum: 30}
validates :last_name, presence:true
validates :address, presence:true
validates :post_number, presence:true
validates :city, presence:true
validates :country, presence:true
validates :mobile, presence:true
def login=(login)
@login = login
end
def login
@login || self.username || self.email
end
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(conditions).where(["username = :value OR lower(email) = lower(:value)", { :value => login }]).first
else
where(conditions).first
end
end
end
这是我的应用程序控制器
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me, :name, :last_name, :address, :post_number, :city, :country_id, :mobile) end
devise_parameter_sanitizer.for(:sign_in) do |u| u.permit(:login, :username, :email, :password, :remember_me) end
devise_parameter_sanitizer.for(:account_update) do |u| u.permit(:username, :email, :password, :password_confirmation, :current_password, :name, :last_name, :address, :post_number, :city, :country_id, :mobile) end
end
end
我在使用 Devise gem 将额外的用户字段值插入数据库时遇到问题。我缺少什么?
我正在使用
ruby 2.1.5p273
Rails 4.1.8
这是我的user.rb模型
class User < ActiveRecord::Base
belongs_to :country
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :authentication_keys => [:login]
attr_accessor :login, :name, :last_name, :address, :post_number, :city, :mobile
validates :username, presence: true, length: {maximum: 25}, :uniqueness => { :case_sensitive => false }
validates :name, presence:true
validates :last_name, presence:true
validates :address, presence:true
validates :post_number, presence:true
validates :city, presence:true
validates :country, presence:true
validates :mobile, presence:true
def login=(login)
@login = login
end
def login
@login || self.username || self.email
end
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(conditions).where(["username = :value OR lower(email) = lower(:value)", { :value => login }]).first
else
where(conditions).first
end
end
end
我的应用控制器
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username << :email << :password << :password_confirmation << :remember_me << :name << :last_name << :address << :post_number << :city << :country_id << :mobile
devise_parameter_sanitizer.for(:sign_in) << :login << :username << :email << :password << :remember_me
devise_parameter_sanitizer.for(:account_update) << :username << :email << :password << :password_confirmation << :current_password << :name << :last_name << :address << :post_number << :city << :country_id << :mobile
end
end
应用程序控制器(V2,我试过船路)
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me, :name, :last_name, :address, :post_number, :city, :country_id, :mobile) }
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :username, :email, :password, :remember_me) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :email, :password, :password_confirmation, :current_password, :name, :last_name, :address, :post_number, :city, :country_id, :mobile) }
end
end
Registratiions/new.html.erb
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :username %><br />
<%= f.text_field :username, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if @validatable %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<hr>
<div>
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div>
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
</div>
<div>
<%= f.label :address %><br />
<%= f.text_field :address %>
</div>
<div>
<%= f.label :post_number %><br />
<%= f.text_field :post_number %>
</div>
<div>
<%= f.label :city %><br />
<%= f.text_field :city %>
</div>
<div>
<%= f.label :country_id %><br />
<%= f.select(:country_id, options_from_collection_for_select(Country.all, :id, :name)) %>
</div>
<div>
<%= f.label :mobile %><br />
<%= f.text_field :mobile %>
</div>
<br><br>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
这是我提交表单时发生的事情的日志
Started POST "/users" for 127.0.0.1 at 2015-01-12 21:29:36 +0100
Processing by RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"YXPl+X5Xpib9yG4ywUY2BAOmiGdNUtkQZtIgxqBXbak=", "user"=>{"email"=>"test@gmail.com", "username"=>"testUser", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "name"=>"Test", "last_name"=>"Test", "address"=>"Test", "post_number"=>"21332", "city"=>"TestCity", "country_id"=>"81831761", "mobile"=>"333666333666"}, "commit"=>"Sign up"}
(0.1ms) begin transaction
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'test@gmail.com' LIMIT 1
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."username") = LOWER('testUser') LIMIT 1
Country Load (0.0ms) SELECT "countries".* FROM "countries" WHERE "countries"."id" = ? LIMIT 1 [["id", 81831761]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = '0ddbdfeadb0c6758be3dda41b068fd319e0fd63cefcb16c5b985f90ab16e6784' ORDER BY "users"."id" ASC LIMIT 1
Binary data inserted for `string` type on column `confirmation_token`
Binary data inserted for `string` type on column `encrypted_password`
SQL (0.3ms) INSERT INTO "users" ("confirmation_sent_at", "confirmation_token", "country_id", "created_at", "email", "encrypted_password", "updated_at", "username") VALUES (?, ?, ?, ?, ?, ?, ?, ?) [["confirmation_sent_at", "2015-01-12 20:29:36.962365"], ["confirmation_token", "0ddbdfeadb0c6758be3dda41b068fd319e0fd63cefcb16c5b985f90ab16e6784"], ["country_id", 81831761], ["created_at", "2015-01-12 20:29:36.742990"], ["email", "test@gmail.com"], ["encrypted_password", "a$bL6dOOVGzfJ5eOGA8mU/ces7w1CCjJk8Z8rlj6BvSQyqbLgazqrVW"], ["updated_at", "2015-01-12 20:29:36.742990"], ["username", "testUser"]]
Rendered devise/mailer/confirmation_instructions.html.erb (0.8ms)
我有两个问题:
- 我必须做什么,所以设计将扩展他的 INSERT sql 查询以插入额外的数据库字段值?
- 应用控制器devise_parameter_sanitizer哪种写法是正确的?
谢谢帮助
我找到了解决办法! 在 rails 4 中,您必须在 controller
中指定 user_params这是我的users_controller(添加user_params)
class UsersController < ApplicationController
def index
@users = User.all
end
def new
@user = User.new
end
private
def user_params
params.require(:user).permit(:username, :email, :password, :password_confirmation, :remember_me, :name, :last_name, :address, :post_number, :city, :country_id, :mobile)
end
end
这是我的用户模型(已删除attr_accessor)
class User < ActiveRecord::Base
belongs_to :country
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :authentication_keys => [:login]
validates :username, presence: true, length: {maximum: 25}, :uniqueness => { :case_sensitive => false }
validates :name, presence:true, length: {maximum: 30}
validates :last_name, presence:true
validates :address, presence:true
validates :post_number, presence:true
validates :city, presence:true
validates :country, presence:true
validates :mobile, presence:true
def login=(login)
@login = login
end
def login
@login || self.username || self.email
end
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(conditions).where(["username = :value OR lower(email) = lower(:value)", { :value => login }]).first
else
where(conditions).first
end
end
end
这是我的应用程序控制器
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me, :name, :last_name, :address, :post_number, :city, :country_id, :mobile) end
devise_parameter_sanitizer.for(:sign_in) do |u| u.permit(:login, :username, :email, :password, :remember_me) end
devise_parameter_sanitizer.for(:account_update) do |u| u.permit(:username, :email, :password, :password_confirmation, :current_password, :name, :last_name, :address, :post_number, :city, :country_id, :mobile) end
end
end