Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using rails validations to determine views

So I've taken fat model skinny controller to heart.

I've moved a lot of checks (i.e. on the creation of a new object) from the controller to the model using validations. Is there a way to leverage my now robust suite of validations from the controller to determine what should show in my views? I'm thinking:

# in the controller
@item = Item.new if valid?

# then in the view:
<% if @item %><%= #button to create new item %>...

Another use case:

<% if @comment.valid? %><div class="new comment"></div><% end %>

I'm going to need to pass in "dummy" values for some of the fields to get the validation to pass, but I'm mostly concerned about "is that user allowed to do that" type stuff. Sorry for the philosophical question, but what's the best practice here?

Update

Here's an example of a permission validation that I have. I'd like stay DRY and use this instead of copy and pasting it to a controller if possible.

class Comment < ActiveRecord::Base

  belongs_to :user
  belongs_to :commentable, :polymorphic => true
  validate :user_can_comment, :if => :user

  def user_can_comment
    errors.add(:user, "can't comment") unless (user.is_photographer || user.id == commentable.user_id)
  end

end
like image 776
brittohalloran Avatar asked Jun 03 '26 10:06

brittohalloran


1 Answers

Looks like you're mixing concerns here. Validations are not meant to be used for access control. Valid users may or may not have access to certain parts of the app, invalid users should never be created in the first place. Invalid users do exist, but only during the rendering of the form with error messages. They are never saved.

Validations

The most basic scaffold controller in rails would show you what controller should look like.

# Example of registration form

class UsersController < ApplicationController

  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])

    if @user.save
      redirect_to root_url, notice: 'Welcome!'
    else
      render :new
    end
  end
end

In the above code pay attention to the line which says render :new. That's what happens when @user could not be saved. Why couldn't it? Because validations failed. How do you know which validations failed? By looking at the @user.errors, which is populated for you. That's why we render and not redirect. As soon as you redirect, the @user.errors array would not exist anymore. So in your view you'd just walk over @user.errors.full_messages and display them nicely.

Permissions

Permissions is a whole different story. If your users can be, say, admins, then you probably have a boolean column on your users table called admin. This will automatically give you @user.admin? method. In your controllers and views you will have current_user based on session, so you can use current_user.admin?. A lot of people do the following in their ApplicationController.

class ApplicationController < ActionController::Base
  # ...

  helper_method :admin?

  def admin?
    current_user.present? && current_user.admin?
  end
end

This will give all your controllers and views a method called admin? which you can use to determine whether something can be accessed by the user. More complicated permissions require using roles. There is a nice library called CanCan from Ryan Bates, which could help with that.

like image 161
Max Chernyak Avatar answered Jun 06 '26 05:06

Max Chernyak



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!