我对Rails和Ruby一般都是新手。我目前正在开展个人项目,在允许用户注册之前,我必须检查用户是否至少13岁。我为此目的使用自定义验证方法,称为check_age_is_above_13
。我遇到的问题是我视图中的date_select
帮助将日期分为dob(1i)
,dob(2i)
和dob(3i)
,我无法弄清楚如何在User
模型中访问这些。我的代码如下:
迁移:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email, null: false
t.string :encrypted_password, null: false
t.string :first_name
t.string :last_name
t.string :gender
t.datetime :dob #date of birth
t.timestamps
end
end
end
User
模型如下所示。我跟踪了here找到的代码段,但我必须承认它有点..... out- 约会:
class User < ActiveRecord::Base
#using Devise for Auth
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :trackable,
:confirmable
validates :gender, inclusion: { in: %w(female male unknown) }
validate :check_age_is_above_13
def check_age_is_above_13
#The following raises "undefined local variable or method `params'" exception
dob = Date.new params[:user]['dob(1i)'].to_i, params[:user]['dob(2i)'].to_i, params[:user]['dob(3i)'].to_i
#Trying the below code raises a "TypeError, expected numeric" exception,
#which is understandable, as "dob" does not exist in the params list
if ((Date.today - dob) / 365.25).to_i < 13
errors.add(:dob, "You must be at least 13 years old to register with us")
end
end
end
POST注册表单时的参数如下所示:
{"utf8"=>"✓",
"authenticity_token"=>"49w4ylxRIDyuRTDASW+vsuFL6Q3eeWcyokKrNXt9taM=",
"user"=>{"email"=>"benny.lava@buffalax.org",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]",
"first_name"=>"Benny",
"last_name"=>"Lava",
"gender"=>"male",
"location_id"=>"1",
"dob(1i)"=>"2001",
"dob(2i)"=>"8",
"dob(3i)"=>"27"},
"commit"=>"Sign up"}
如何访问模型中的dob(Xi)
参数,以便在对其执行自定义验证之前,先将它们转换为Date
对象?我使用Devise进行用户身份验证和注册,如果它有任何区别的话。
编辑:视图如下所示:
<h2>Sign Up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div>
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div>
<%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div>
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div>
<%= f.label :first_name %><br/>
<%= f.text_field :first_name %>
</div>
<div>
<%= f.label :last_name %><br/>
<%= f.text_field :last_name %>
</div>
<div>
<%= f.label :gender %><br/>
<%= f.select :gender, options_for_select(%w[female male -]) %>
</div>
<div>
<%= f.label :location_id %><br/>
<%= f.select :location_id, options_for_select(Location.all.collect { |l| [l.name, l.id]}), {:include_blank => false} %>
</div>
<div>
<%= f.label :dob, "Date of Birth" %><br/>
<%= f.date_select :dob, {include_blank: false, start_year: Date.today.year - 100, end_year: Date.today.year - 13, default: {day: 31, month: 1, year: 1991}} %>
</div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
答案 0 :(得分:1)
您可以从控制器访问params
哈希并查看图层,但不能从模型图层访问。因此,尝试在Date
模型中创建User
对象有点太晚了。严格地说,您应该已经在控制器阶段填写了dob
日期,但如果没有,我建议您覆盖设计控制器的create
方法并设置dob
变量在验证user
之前,在那里用手。只是为了澄清,省略了设计的重要部分,你需要这样的东西:
class Users::RegistrationsController < Devise::RegistrationsController
# POST /resource/sign_up
def create
build_resource
resource.dob = Date.new params[:user]['dob(1i)'].to_i, params[:user]['dob(2i)'].to_i, params[:user]['dob(3i)'].to_i
if resource.save
set_flash_message :notice, :signed_up
sign_in_and_redirect(resource_name, resource)
else
clean_up_passwords(resource)
render_with_scope :new
end
end
end
完成此操作后,您应该从dob
模型验证方法中删除User
分配行,因为您已经设置了dob
。
如果您不知道从哪里开始,请查看this gist包含有关覆盖设计控制器的提示。
答案 1 :(得分:1)
严格来说,你可能不应该(并且不应该)访问rails中控制器之外的参数。
您的模型创建生命周期应如下所示:
用户输入字段
编辑看起来基本相同,只是它在控制器中使用编辑和更新方法,而模型ID通常是网址的一部分。
无论如何,如果你在控制器中正确地创建用户实例,那么在验证中你应该能够简单地调用self.dob(甚至只是dob)来访问应该是用户的内容&#39;输入的出生日期。因为您的迁移应该适当地作为某种日期。
在您的控制器中,用户创建方法可能类似于:
def create
@user = User.new(params[:user])
if (@user.save)
# respond/redirect
else
# respond/redirect
end
end
正如您所看到的,@ user在创建时已经从params中获得了这些值,因此您应该可以在验证中访问它们。