验证仅在表单中的值

时间:2022-11-28 16:42:39

I asked this kind of question yesterday, but after I worked on the problem couple of hours, I learned that, the question I asked yesterday wan't the problem I was having. So, I decided to ask again.

我昨天问了这个问题,但是在我解决了几个小时的问题后,我才知道,我昨天问的问题不是我遇到的问题。所以,我决定再问一次。

User Model:

  EMAIL_REGEX = /\A^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$\z/
  # Matches -> he_llo@worl.d.com  hel.l-o@wor-ld.museum  h1ello@123.com
  # Non-Matches -> hello@worl_d.com  he&llo@world.co1  .hello@wor#.co.uk
  # http://regexlib.com/REDetails.aspx?regexp_id=333

  ALL_LETTERS_AND_SINGLE_SPACES = /\A^([a-zA-Z]+\s?)*$\z/
  ALL_LETTERS_AND_NUMBERS = /\A^[a-zA-Z0-9]+$\z/
  WEBSITE = /\A(www.)?([a-zA-Z0-9]+).[a-zA-Z0-9]*.[a-z]{3}.?([a-z]+)?\z/

  # First Name
  validates :first_name,
            presence: {message: 'First name cannot be blank'},
            length: {maximum: 50, message: 'First name cannot be longer than 50 characters'},
            format: {with: ALL_LETTERS_AND_SINGLE_SPACES, message: 'First name should contain only letters and single space'}

  # Last Name
  validates :last_name,
            presence: {message: 'Last name cannot be blank'},
            length: {maximum: 50, message: 'Last name cannot be longer than 50 characters'},
            format: {with: ALL_LETTERS_AND_SINGLE_SPACES, message: 'Last name should contain only letters and single space'}

  # Email
  validates :email,
            presence: {message: 'Email cannot be blank'},
            length: {maximum: 100, message: 'Email cannot be longer than 100 characters'},
            format: {with: EMAIL_REGEX, message: 'Email is not valid'},
            uniqueness: {case_sensitive: false, message: 'This email is already registered'},
            confirmation: {message: 'Email address does not match'}

  # Password
  validates :password_digest,
            presence: {message: 'Password cannot be blank'},
            length: {minimum: 8, message: 'Password length should be minimum 8 characters'}

  # Username
  validates :username,
            presence: {message: 'Username cannot be blank'},
            length: {minimum: 3, message: 'Email cannot be shorter than 3 characters'},
            format: {with: ALL_LETTERS_AND_NUMBERS, message: 'Username should contain only letters and numbers'},
            uniqueness: {case_sensitive: false, message: 'This username is already in use'}

  # Website
  validates :website,
            format: {with: WEBSITE, message: 'Invalid email format. Make sure you don\'t have http:// in your link'}

  # Information
  validates :information,
            length: {maximum: 100, message: 'Information cannot be longer than 99 characters'}

As you can see, I have validation for some of the columns in my database. What I need is to validate first_name, last_name, email, and password when user is signing up, and validate first_name, last_name, and also website, information, username when user editing his/her profile settings.

如您所见,我对数据库中的某些列进行了验证。我需要的是在用户注册时验证first_name,last_name,电子邮件和密码,并在用户编辑他/她的配置文件设置时验证first_name,last_name以及网站,信息,用户名。

But rails is automatically validating all the columns either you have username field in your signup page or not. It just validates everything. But I don't want rails to validate username, or website when signing up.

但是rails会自动验证您在注册页面中是否有用户名字段的所有列。它只是验证了一切。但我不希望rails在注册时验证用户名或网站。

Profile Controller:

  def update
    # Find an existing object using form parameters
    @profile = User.find_by_id(current_user.id)
    # Update the object
    if @profile.update_attributes!(settings_profile_params)
      # If save succeeds, redirect to itself
      redirect_to request.referrer
    else
      # If save fails, redisplay the form so user can fix the problems
      render('edit')
    end
  end

  private # user_params is not an action, that is why it is private.
  def settings_profile_params
    params.require(:user).permit(:first_name, :last_name, :username, :school, :program, :website, :information)
  end 

Users Controller:

  def create
    # Instantiate a new object using form parameters
    @user = User.new(user_params)
    # Save the object
    if @user.save
      # If save succeeds, redirect to the dashboard action
      cookies[:authorization_token] = @user.authorization_token
      redirect_to dashboard_path
    else
      # If save fails, redisplay the form so user can fix the problems
      render('new')
    end
  end

  private # user_params is not an action, that is why it is private.
  def user_params
    params.require(:user).permit(:first_name, :last_name, :email, :email_confirmation, :password)
  end

I thought rails would validate the ones that are passed in strong parameters only but it's not. I believe it supposed to be very easy to solve but I can't.

我认为rails会验证仅在强参数中传递的那些,但事实并非如此。我相信它应该很容易解决,但我不能。

Thank you.

3 个解决方案

#1


1  

I don't know of an idiomatic way to to do this. For individual validations you want to only run on update, you can do

我不知道这样做的惯用方法。对于您希望仅在更新时运行的个人验证,您可以这样做

validates :username,
...
on: :update # or on: :create

Or if you want them only to run when the attribute has been provided in the form,

或者,如果您希望它们仅在表单中提供属性时运行,

validates :username,
...
if: :username_changed?

For a more radical solution, you may want to consider breaking your model up into two--one containing the attributes created on signup (User), and one with the rest of the attributes (a UserDetails or UserProfile) that belongs_to :user. At that point, having different validation logic at different stages in your workflow becomes simple.

对于更激进的解决方案,您可能需要考虑将模型分解为两个 - 一个包含在注册(User)上创建的属性,另一个包含belongs_to:user的其余属性(UserDetails或UserProfile)。此时,在工作流程的不同阶段使用不同的验证逻辑变得简单。

#2


0  

Validations in models are most of the time about forms.

模型中的验证大部分时间都是关于表单的。

Ryan Bates has issued an excellent RailsCast on how to refactor your model, in a way that you use a different object for each one of your forms.

Ryan Bates发布了一个关于如何重构模型的优秀RailsCast,其方式是为每个表单使用不同的对象。

This way, you can combine models and/or define different behaviours and/or validations, depending on the form that submits the data.

这样,您可以组合模型和/或定义不同的行为和/或验证,具体取决于提交数据的表单。

The way to do it is quite long to describe, so posting code here would be messy.

这样做的方式很难描述,所以在这里发布代码会很混乱。

I strongly suggest visiting the above link, you will have your answer there.

我强烈建议您访问以上链接,您将在那里得到答案。

#3


-1  

You can use :if option:

您可以使用:if选项:

class Order < ActiveRecord::Base
  validates :card_number, presence: true, if: :paid_with_card?

  def paid_with_card?
    payment_type == "card"
  end
end

But I think you're looking for allow_nil or allow_blank option:

但我认为你正在寻找allow_nil或allow_blank选项:

3.1 :allow_nil

The :allow_nil option skips the validation when the value being validated is nil.

当验证的值为nil时,:allow_nil选项会跳过验证。

class Coffee < ActiveRecord::Base
  validates :size, inclusion: { in: %w(small medium large),
    message: "%{value} is not a valid size" }, allow_nil: true
end

3.2 :allow_blank

The :allow_blank option is similar to the :allow_nil option. This option will let validation pass if the attribute's value is blank?, like nil or an empty string for example.

:allow_blank选项类似于:allow_nil选项。如果属性的值为空,则此选项将允许验证通过?,例如nil或空字符串。

class Topic < ActiveRecord::Base
  validates :title, length: { is: 5 }, allow_blank: true
end

Topic.create(title: "").valid?  # => true
Topic.create(title: nil).valid? # => true

#1


1  

I don't know of an idiomatic way to to do this. For individual validations you want to only run on update, you can do

我不知道这样做的惯用方法。对于您希望仅在更新时运行的个人验证,您可以这样做

validates :username,
...
on: :update # or on: :create

Or if you want them only to run when the attribute has been provided in the form,

或者,如果您希望它们仅在表单中提供属性时运行,

validates :username,
...
if: :username_changed?

For a more radical solution, you may want to consider breaking your model up into two--one containing the attributes created on signup (User), and one with the rest of the attributes (a UserDetails or UserProfile) that belongs_to :user. At that point, having different validation logic at different stages in your workflow becomes simple.

对于更激进的解决方案,您可能需要考虑将模型分解为两个 - 一个包含在注册(User)上创建的属性,另一个包含belongs_to:user的其余属性(UserDetails或UserProfile)。此时,在工作流程的不同阶段使用不同的验证逻辑变得简单。

#2


0  

Validations in models are most of the time about forms.

模型中的验证大部分时间都是关于表单的。

Ryan Bates has issued an excellent RailsCast on how to refactor your model, in a way that you use a different object for each one of your forms.

Ryan Bates发布了一个关于如何重构模型的优秀RailsCast,其方式是为每个表单使用不同的对象。

This way, you can combine models and/or define different behaviours and/or validations, depending on the form that submits the data.

这样,您可以组合模型和/或定义不同的行为和/或验证,具体取决于提交数据的表单。

The way to do it is quite long to describe, so posting code here would be messy.

这样做的方式很难描述,所以在这里发布代码会很混乱。

I strongly suggest visiting the above link, you will have your answer there.

我强烈建议您访问以上链接,您将在那里得到答案。

#3


-1  

You can use :if option:

您可以使用:if选项:

class Order < ActiveRecord::Base
  validates :card_number, presence: true, if: :paid_with_card?

  def paid_with_card?
    payment_type == "card"
  end
end

But I think you're looking for allow_nil or allow_blank option:

但我认为你正在寻找allow_nil或allow_blank选项:

3.1 :allow_nil

The :allow_nil option skips the validation when the value being validated is nil.

当验证的值为nil时,:allow_nil选项会跳过验证。

class Coffee < ActiveRecord::Base
  validates :size, inclusion: { in: %w(small medium large),
    message: "%{value} is not a valid size" }, allow_nil: true
end

3.2 :allow_blank

The :allow_blank option is similar to the :allow_nil option. This option will let validation pass if the attribute's value is blank?, like nil or an empty string for example.

:allow_blank选项类似于:allow_nil选项。如果属性的值为空,则此选项将允许验证通过?,例如nil或空字符串。

class Topic < ActiveRecord::Base
  validates :title, length: { is: 5 }, allow_blank: true
end

Topic.create(title: "").valid?  # => true
Topic.create(title: nil).valid? # => true