ScopedAttributes
scoped_attributes provides a module that allows you to add access restriction settings to attributes. By using this, you can easily create a wrapper model that returns only the information required for each different role. I think it can also be used to API Scope and view models.
Installation
Add this line to your application's Gemfile:
gem 'scoped_attributes'
Usage
You can create a wrapper model by including the ScopedAttributes module.
class ApplicationScopedModel
include ScopedAttributes
roles :admin, :manager
def admin?
user.admin?
end
def manager?
user.manager?
end
end
class ScopedCrew < ApplicationScopedModel
attribute :id
attribute :name
attribute :address, only: proc { me? || admin? } # Proc
attribute :evaluation, only: %i(admin) # role names (Array)
def me?
id == user.crew_id
end
end
When using with ActiveRecord object
Specify the target object in the first argument and the user with the role in the second argument. The acquisition of the attribute is controlled by the condition specified in attribute class macro.
For an ActiveRecord object, you can use the to_model method to get the model instance with the attribute selected.
# current_user is not admin and not me
scoped_crew = ScopedCrew.new(Crew.find(1), current_user)
scoped_crew.name
# => "hoge"
scoped_crew.address
# => nil
scoped_crew.attributes
# => {:id=>1, :name=>"hoge"}
scoped_crew.to_model
# => #<Crew:xxx id: 1, name: "hoge">
Crew.find(1).scoped(current_user)
# => #<Crew:xxx id: 1, name: "hoge">
# current_user is not admin but is me
scoped_crew = ScopedCrew.new(Crew.find(1), current_user)
scoped_crew.name
# => "hoge"
scoped_crew.address
# => "tokyo"
scoped_crew.attributes
# => {:id=>1, :name=>"hoge", :address=>"tokyo"}
scoped_crew.to_model
# => #<Crew:xxx id: 1, name: "hoge", address: "tokyo">
Crew.find(1).scoped(current_user)
# => #<Crew:xxx id: 1, name: "hoge", address: "tokyo">
# current_user is admin
scoped_crew = ScopedCrew.new(Crew.find(1), current_user)
scoped_crew.name
# => "hoge"
scoped_crew.address
# => "tokyo"
scoped_crew.attributes
# => {:id=>1, :name=>"hoge", :address=>"tokyo", :evaluation=>"SS"}
scoped_crew.to_model
# => #<Crew:xxx id: 1, name: "hoge", address: "tokyo", evaluation: "SS">
Crew.find(1).scoped(current_user)
# => #<Crew:xxx id: 1, name: "hoge", address: "tokyo", evaluation: "SS">
When using with PORO
ScopedAttributes module can also be used by including it in PORO(Plain Old Ruby Object).
class ScopedCrew < ApplicationScopedModel
attribute :name
attribute :addres
attribute :evaluation, only: %i(admin)
end
class CustomCrew
attr_accessor :name, :address, :evaluation
def initialize(name, address, evaluation)
self.name = name
self.address = address
self.evaluation = evaluation
end
end
crew = CustomCrew.new("hoge", "tokyo", "SS")
scoped_crew = ScopedCrew.new(crew, current_user)
scoped_crew.attributes
# => {:name=>"hoge", :address=>"tokyo"}
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/shunhikita/scoped_attributes.