MonthJuly 2013

How to manage users in Rails 4 (using devise)

Devise is currently the most used gem for authentication in Rails, and version 3.0.0 is compatible with Rails 4. For this, and for being powerful and configurable and staying out of the way (at least initially), I’ve chosen devise for my current project.

To generate a User model I left it to devise itself by issuing

$ rails generate devise MODEL
$ rake db:migrate

Al went fine, but when I wanted to be able to also do some CRUD myself on User models, I issued

$ rails generate scaffold_controller User –skip

At this point I had to fix the form helper and a couple of views, for adding email, password and password_confirmation fields. Then the controller too needed some adjustments that were a little more difficult go get properly, but the model was already fine.

The problem with the controller was changing the update action so that I’d be able to edit the email and/or the password independently.

Here is my new update

  # PATCH/PUT /users/1
  # PATCH/PUT /users/1.json
  def update
    if user_params[:password].blank?

    successfully_updated = if needs_password?(@user, user_params)

    respond_to do |format|
      if successfully_updated
        format.html { redirect_to @user, notice: 'User was successfully updated.' }
        format.json { head :no_content }
        format.html { render action: 'edit' }
        format.json { render json: @user.errors, status: :unprocessable_entity }

And here is the private defs for user_params and needs_password?

  # Never trust parameters from the scary internet, only allow the white list through.
  def user_params
    params.require(:user).permit(:email, :password, :password_confirmation)

  def needs_password?(user, params)

So the difficult part here was that you have to use the normal update method when you also want to change the password and the special update_without_password method (provided by devise) when you don’t want to change the password.

Devise also provides an update_with_password method, but that’s misleading because it requires the current_password field, only useful when you want the user herself to be able to edit her data. It should be renamed to update_with_current_password…


How to validate dates in Rails 4

During the past few days I’ve been busy looking for existing gems doing date validation in Rails 4. I’ve tried a couple of the most famous, but they were compatible with Rails only up to 3.2, so I decided to write a solution myself.

It works fine for me. I’m not going to convert it to a gem because I don’t have time to learn how to right now. If you want to help, you’re welcome.


It’s all very straightforward.

  • The validator symbol is :date.
  • The validator really does nothing if you don’t provide any options…
  • Supported options are :after, :before, :on_or_after, and :on_or_before, plus :message.
  • If the message is not provided a fine default one is used instead.
  • Values of supported options can be date-castable objects, lambdas, or symbols.
  • Symbols must be method names of the validating object or its class.
  • Values are computed (if needed) and converted to date on each validation.


Here is my DateValidator class, to be put into the app/validators folder.

class DateValidator < ActiveModel::EachValidator

  attr_accessor :computed_options

  def before(a, b);       a < b;  end
  def after(a, b);        a > b;  end
  def on_or_before(a, b); a <= b; end
  def on_or_after(a, b);  a >= b; end

  def checks
    %w(before after on_or_before on_or_after)

  def message_limits
    needs_and =
        (computed_options[:on_or_after]  || computed_options[:after]) &&
        (computed_options[:on_or_before] || computed_options[:before])

    result = ['must be a date']
    result.push('on or after',  computed_options[:on_or_after])  if computed_options[:on_or_after]
    result.push('after',        computed_options[:after])        if computed_options[:after]
    result.push('and')                                           if needs_and
    result.push('on or before', computed_options[:on_or_before]) if computed_options[:on_or_before]
    result.push('before',       computed_options[:before])       if computed_options[:before]
    result.join(' ')

  def compute_options(record)
    result = {}
    options.each do |key, val|
      next unless checks.include?(key.to_s)
      if val.respond_to?(:lambda?) and val.lambda?
        val =
      elsif val.is_a? Symbol
        if record.respond_to?(val)
          val = record.send(val)
        elsif record.class.respond_to?(val)
          val = record.class.send(val)
      result[key] = val.to_date
    self.computed_options = result

  def validate_each(record, attribute, value)
    return unless value.present?

    return unless options
    compute_options(record) # do not cache this
                            # otherwise all the 'compute' thing is useless... #
    computed_options.each do |key, val|
      unless self.send(key, value, val)
        record.errors[attribute] << (computed_options[:message] || message_limits)

Here is an example of how to use it into a model.

class UserProfile < ActiveRecord::Base

  validates :name,       presence: true
  validates :birth_date, presence: true, date: {on_or_after: :birth_date_first, on_or_before: :birth_date_last}

  def self.birth_date_first

  def self.birth_date_last


Here is the form helper snippet (only what differs from scaffolding).

  <div class="field">
    <%= f.label :birth_date %><br>
    <%= f.date_field :birth_date, min: UserProfile.birth_date_first, max: UserProfile.birth_date_last %>

Here is the controller snippet (only what differs from scaffolding).

  # GET /user_profiles/new
  def new
    @user_profile =
    @user_profile.birth_date = 25.years.ago # this is the default value for new records
                                            # I tried to use the :value option in the date_field helper
                                            # but it overrides the value in the record also when editing... #


© 2017 Notes Log

Theme by Anders NorenUp ↑