Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Deepak Singh
Deepak Singh

Posted on

     

Clean Validations with Custom Contexts

Active Record validations are a well-known and widely used in Rails.

class User < ApplicationRecord  validates :name, presence: { message: "must be given please" }end
Enter fullscreen modeExit fullscreen mode

This runs the validation onsave, both when creating a new record or when updating an existing record.

on option allows control over when to run the validation, commonly used with value ofcreate orupdate

class User < ApplicationRecord  belongs_to :club, optional: true   validates :name, presence: { message: "must be given please" }, on: :create  validates :club, presence: { message: "must be given please" }, on: :update  end
Enter fullscreen modeExit fullscreen mode

This allows creating users without associating them with a Club, but enforces presence of Club on subsequent updates. This pattern is commonly used to allow users to signup with bare minimum form fields and then forcing them to update their profiles with more information on subsequent visits.

Value for theon option is not limited tocreate andupdate, we can have our own custom contexts. Like in a multistep form, we can have validations for each of the steps.on options makes this really easy to do

class User < ApplicationRecord  validate :basic_info, on: :basic_info  validate :education_details, on: :education_details  validate :professional_info, on: :professional_info  private  def basic_info    # Validation for basic info, first_name, last_name, email  end  def education_details    # Validation for education_details  end  def professional_info    # Validation for professional_info  endend
Enter fullscreen modeExit fullscreen mode

In the controller

class UsersController < ApplicationController  ...  def update_basic_info    @user.assign_attributes(basic_info_params)    @user.save(:basic_info)  end  def update_education_details    @user.assign_attributes(education_details_params)    @user.save(:education_details)  end  def update_professional_info    @user.assign_attributes(professional_info_params)    @user.save(:professional_info)  end  private  def basic_info_params    # strong params  end  def education_details_params    # strong params  end  def professional_info_params    # strong params  endend
Enter fullscreen modeExit fullscreen mode

With Rails 5 adding support for multiple contexts, we can use multiple context together

@user.save(:basic_info, :professional_info)
Enter fullscreen modeExit fullscreen mode

This seems pretty neat, let's go a step further and do this withupdate_attributes. In current implementation of Rails,
update_attributes does not support validation contexts. We can get around this by defining our own custom method

class ApplicationRecord < ActiveRecord::Base  self.abstract_class = true  def update_attibutes_with_context(attributes, *contexts)    with_transaction_returning_status do      assign_attributes(attributes)      save(context: contexts)    end  endend
Enter fullscreen modeExit fullscreen mode

In the controller

@user.update_attibutes_with_context({first_name: 'fname'}, :basic_info)
Enter fullscreen modeExit fullscreen mode

Lastly, we can usewith_options to group multiple validation within a context

  with_options on: :member do |member_user|    member_user.validates :club_name, presence: true    member_user.validates :membership_id, presence: true  end
Enter fullscreen modeExit fullscreen mode

This makes really easy to write readable and maintainable code, with a good separation of concerns.

Read my last post on ActiveRecord Validations herehttps://dev.to/spidergears/rails-active-record-validation-messages-4dcf

Top comments(2)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
playwright2poli profile image
playwrightpo
  • Joined

Thanks for the article!
I have not usedon option with custom context, it is interesting approach. But I think it should be used very rarely, because of otherwise we are about to get bloated models with many responsibilities. In most cases such a things would be better to incapsulate out of models, e.g. by using form objects..

CollapseExpand
 
__deepak__ profile image
Deepak Singh
Co-founder Eloquent.Studio | Ruby on Rails, Go, React
  • Location
    Pune, India
  • Work
    Co-founder and Director at Eloquent Studio Private Limited
  • Joined

Absolutely agree with you, should be used only when it fits the case.

Example is for demonstration and to hint at capabilities of the framework, form object are much more suitable for the scenario.

Thanks for going through, and putting out your thoughts. :)

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Co-founder Eloquent.Studio | Ruby on Rails, Go, React
  • Location
    Pune, India
  • Work
    Co-founder and Director at Eloquent Studio Private Limited
  • Joined

More fromDeepak Singh

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp