Question

I have a Page Model that has a :name attribute. I have a specific route for the Page Model with the name "home", because I want this specific Page record to be found at the root_url. This works.. but because I'm hard coding the route... I only want users with the role "super_admin" to be able to change the :name attribute, on the Page model, where the name == "home". For example, users with the "admin" role should not be able to change the :name attribute on the "home" Page.

  1. Can I get that fine grained with CanCan?
  2. Should I put this logic in the PageControllers update action?
  3. Should I set the "page#show" route differently (not hard code it)?

Not sure how to do any of these. Thanks in advance for any advice!

ability.rb

elsif user.role == "admin"
  can :manage, :all
  cannot :update, Page, ["name == ?", "home"] do |page|
    page.name == "home"
  end
end

routes.rb (I'm using friendly_id to generate a slug from the :name attribute)

match '/:slug', :to => "pages#show", :as => :slug, :via => :get
root :to => 'pages', :controllers => "pages", :action => "show", :slug => "home"

pages_controller.rb (standard)

def update
  @page = Page.find(params[:id])

  respond_to do |format|
    if @page.update_attributes(params[:page])
      format.html { redirect_to @page, notice: 'Page was successfully updated.' }
      format.json { head :no_content }
    else
      format.html { render action: "edit" }
      format.json { render json: @page.errors, status: :unprocessable_entity }
    end
  end
end
Was it helpful?

Solution

I must admit, I've read your question three times, and I think I have answers for you...

1 - Yes, I believe so. However, I'm not convinced your ability.rb code is correct. I'd aim for something closer to this:

cannot :update, Page do |page|
  page.name == "home"
end

2 - If you do load_and_authorize_resource in your controller, that should be all you need, because that will load @page for you.

class PagesController < ApplicationController

  load_and_authorize_resource

  def update

    respond_to do |format|
      if @page.update_attributes(params[:page])
        format.html { redirect_to @page, notice: 'Page was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @page.errors, status: :unprocessable_entity }
      end
    end
  end

end

3 - To me, your route looks fine. That's likely the way I'd approach it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top