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?
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
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.
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 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With