Search code examples
ruby-on-railsrubyruby-on-rails-4simple-formcancan

simple_form association accesses record that user doesn't have access rails


I have a Rails 4 App that has a simple association model.

user.rb

has_many :opportunities
has_many :customers
has_many :accounts

opportunity.rb

belongs_to :user
belongs_to :account

customer.rb

belongs_to :user
belongs_to :account

account.rb

belongs_to :user
has_many :opportunities, dependent: :destroy 
has_many :customers, dependent: :destroy

Here's the customer controller

def index
  @customers = Customer.accessible_by(current_ability)
end

def show
  @customers = Customer.find(params[:id])
  @customer.user = current_user
  authorize! :show, @customer
end

def new
  @customer = Customer.new
  @customer.user = current_user
  authorize! :new, @customer
end

def edit
  @customer = Customer.find(params[:id])
  @customer.user = current_user
  authorize! :edit, @customer
end

I have CanCan for ability control;

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user.has_role? :admin
      can :manage, :all
    end
    can :manage, Account, user_id: user.id
    can :manage, Opportunity, user_id: user.id
    can :manage, Customer, user_id: user.id
  end
end

I'm using simple_form to add account associations to customers.

<%=f.association :account,:label => 'Customer Account Name', label_method: :account_name, value_method: :id, include_blank: '-- Select One --' %>

The problem is the association tag seems to be able to access all accounts in the database not just those associated to the user. I can't work it out the association tag seems to ignore any restrictions.

Gem Versions rails, 4.0.4 simple_form, 3.0.2 "cancan"


Solution

  • By default simple form will just include all items for an association. In order to limit the options in the dropdown you'll want to set the collection attribute like so and pass in only the records the user can access, for example:

    <%= f.association :account, :label => 'Customer Account Name', label_method: :account_name, value_method: :id, include_blank: '-- Select One --', collection: Account.accessible_by(current_ability) %>