forked from CanCanCommunity/cancancan
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add active_record_5_adapter and update rails 5.2 from beta2 to rc1 Ca…
- Loading branch information
1 parent
048c516
commit c80a563
Showing
9 changed files
with
196 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
module CanCan | ||
module ModelAdapters | ||
class ActiveRecord5Adapter < ActiveRecord4Adapter | ||
AbstractAdapter.inherited(self) | ||
|
||
def self.for_class?(model_class) | ||
ActiveRecord::VERSION::MAJOR == 5 && model_class <= ActiveRecord::Base | ||
end | ||
|
||
# rails 5 is capable of using strings in enum | ||
# but often people use symbols in rules | ||
def self.matches_condition?(subject, name, value) | ||
return super if Array.wrap(value).all? { |x| x.is_a? Integer } | ||
|
||
attribute = subject.send(name) | ||
if value.is_a?(Enumerable) | ||
value.map(&:to_s).include? attribute | ||
else | ||
attribute == value.to_s | ||
end | ||
end | ||
|
||
private | ||
|
||
# As of rails 4, `includes()` no longer causes active record to | ||
# look inside the where clause to decide to outer join tables | ||
# you're using in the where. Instead, `references()` is required | ||
# in addition to `includes()` to force the outer join. | ||
def build_relation(*where_conditions) | ||
relation = @model_class.where(*where_conditions) | ||
relation = relation.includes(joins).references(joins) if joins.present? | ||
relation | ||
end | ||
|
||
# Rails 4.2 deprecates `sanitize_sql_hash_for_conditions` | ||
def sanitize_sql(conditions) | ||
if conditions.is_a?(Hash) | ||
sanitize_sql_activerecord5(conditions) | ||
else | ||
@model_class.send(:sanitize_sql, conditions) | ||
end | ||
end | ||
|
||
def sanitize_sql_activerecord5(conditions) | ||
table = @model_class.send(:arel_table) | ||
table_metadata = ActiveRecord::TableMetadata.new(@model_class, table) | ||
predicate_builder = ActiveRecord::PredicateBuilder.new(table_metadata) | ||
|
||
conditions = predicate_builder.resolve_column_aliases(conditions) | ||
|
||
conditions.stringify_keys! | ||
|
||
predicate_builder.build_from_hash(conditions).map do |b| | ||
visit_nodes(b) | ||
end.join(' AND ') | ||
end | ||
|
||
def visit_nodes(b) | ||
# Rails 5.2 adds a BindParam node that prevents the visitor method from properly compiling the SQL query | ||
if ActiveRecord::VERSION::MINOR >= 2 | ||
connection = @model_class.send(:connection) | ||
collector = Arel::Collectors::SubstituteBinds.new(connection, Arel::Collectors::SQLString.new) | ||
connection.visitor.accept(b, collector).value | ||
else | ||
@model_class.send(:connection).visitor.compile(b) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
spec/cancan/model_adapters/active_record_5_adapter_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
require 'spec_helper' | ||
|
||
if ActiveRecord::VERSION::MAJOR == 5 && defined?(CanCan::ModelAdapters::ActiveRecord5Adapter) | ||
describe CanCan::ModelAdapters::ActiveRecord5Adapter do | ||
context 'with sqlite3' do | ||
before :each do | ||
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') | ||
ActiveRecord::Migration.verbose = false | ||
ActiveRecord::Schema.define do | ||
create_table(:parents) do |t| | ||
t.timestamps null: false | ||
end | ||
|
||
create_table(:children) do |t| | ||
t.timestamps null: false | ||
t.integer :parent_id | ||
end | ||
end | ||
|
||
class Parent < ActiveRecord::Base | ||
has_many :children, -> { order(id: :desc) } | ||
end | ||
|
||
class Child < ActiveRecord::Base | ||
belongs_to :parent | ||
end | ||
|
||
(@ability = double).extend(CanCan::Ability) | ||
end | ||
|
||
it 'allows filters on enums' do | ||
ActiveRecord::Schema.define do | ||
create_table(:shapes) do |t| | ||
t.integer :color, default: 0, null: false | ||
end | ||
end | ||
|
||
class Shape < ActiveRecord::Base | ||
unless defined_enums.keys.include? 'color' | ||
enum color: %i[red green blue] | ||
end | ||
end | ||
|
||
red = Shape.create!(color: :red) | ||
green = Shape.create!(color: :green) | ||
blue = Shape.create!(color: :blue) | ||
|
||
# A condition with a single value. | ||
@ability.can :read, Shape, color: :green | ||
|
||
expect(@ability.cannot?(:read, red)).to be true | ||
expect(@ability.can?(:read, green)).to be true | ||
expect(@ability.cannot?(:read, blue)).to be true | ||
|
||
accessible = Shape.accessible_by(@ability) | ||
expect(accessible).to contain_exactly(green) | ||
|
||
# A condition with multiple values. | ||
@ability.can :update, Shape, color: %i[red blue] | ||
|
||
expect(@ability.can?(:update, red)).to be true | ||
expect(@ability.cannot?(:update, green)).to be true | ||
expect(@ability.can?(:update, blue)).to be true | ||
|
||
accessible = Shape.accessible_by(@ability, :update) | ||
expect(accessible).to contain_exactly(red, blue) | ||
end | ||
|
||
it 'allows dual filter on enums' do | ||
ActiveRecord::Schema.define do | ||
create_table(:discs) do |t| | ||
t.integer :color, default: 0, null: false | ||
t.integer :shape, default: 3, null: false | ||
end | ||
end | ||
|
||
class Disc < ActiveRecord::Base | ||
enum color: %i[red green blue] unless defined_enums.keys.include? 'color' | ||
enum shape: { triangle: 3, rectangle: 4 } unless defined_enums.keys.include? 'shape' | ||
end | ||
|
||
red_triangle = Disc.create!(color: :red, shape: :triangle) | ||
green_triangle = Disc.create!(color: :green, shape: :triangle) | ||
green_rectangle = Disc.create!(color: :green, shape: :rectangle) | ||
blue_rectangle = Disc.create!(color: :blue, shape: :rectangle) | ||
|
||
# A condition with a dual filter. | ||
@ability.can :read, Disc, color: :green, shape: :rectangle | ||
|
||
expect(@ability.cannot?(:read, red_triangle)).to be true | ||
expect(@ability.cannot?(:read, green_triangle)).to be true | ||
expect(@ability.can?(:read, green_rectangle)).to be true | ||
expect(@ability.cannot?(:read, blue_rectangle)).to be true | ||
|
||
accessible = Disc.accessible_by(@ability) | ||
expect(accessible).to contain_exactly(green_rectangle) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters