Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for attribute alias #592

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/ransack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
module Ransack
extend Configuration
class UntraversableAssociationError < StandardError; end;

SUPPORTS_ATTRIBUTE_ALIAS = begin
ActiveRecord::Base.respond_to?(:attribute_aliases)
rescue NameError
false
end
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know if there are versions of Active Record that do not support attribute_aliases? Or any other cases when this might be false. Just trying to understand 😃

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attribute_aliases was introduced in Rails 4. So 3.x versions do not support it. I haven't found an alternative method in Rails 3.x that retrieves the aliases.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, thanks.

Ransack.configure do |config|
Expand Down
7 changes: 5 additions & 2 deletions lib/ransack/adapters/active_record/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ def ransacker(name, opts = {}, &block)
# Ransackable_attributes, by default, returns all column names
# and any defined ransackers as an array of strings.
# For overriding with a whitelist array of strings.
#
def ransackable_attributes(auth_object = nil)
column_names + _ransackers.keys
if Ransack::SUPPORTS_ATTRIBUTE_ALIAS
column_names + _ransackers.keys + attribute_aliases.keys
else
column_names + _ransackers.keys
end
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could probably just inline the values here without memoizing to a local var:

def ransackable_attributes(auth_object = nil)
  if Ransack::SUPPORTS_ATTRIBUTE_ALIAS
    column_names + _ransackers.keys + attribute_aliases.keys
  else
    column_names + _ransackers.keys
  end
end


# Ransackable_associations, by default, returns the names
Expand Down
11 changes: 9 additions & 2 deletions lib/ransack/nodes/bindable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,17 @@ def get_arel_attribute
if ransacker
ransacker.attr_from(self)
else
context.table_for(parent)[attr_name]
table = context.table_for(parent)
is_alias = Ransack::SUPPORTS_ATTRIBUTE_ALIAS &&
context.klass.attribute_aliases.key?(attr_name)

if is_alias
table[context.klass.attribute_aliases[attr_name]]
else
table[attr_name]
end
end
end

end
end
end
14 changes: 14 additions & 0 deletions spec/ransack/adapters/active_record/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,16 @@ def self.simple_escaping?
expect(s.result.to_a).to eq [p]
end

if Ransack::SUPPORTS_ATTRIBUTE_ALIAS
it "should translate attribute aliased column names" do
s = Person.ransack(:full_name_eq => 'Nicolas Cage')
expect(s.result.to_sql).to match(
/WHERE #{quote_table_name("people")}.#{
quote_column_name("name")}/
)
end
end

it 'allows sort by "only_sort" field' do
s = Person.ransack(
"s" => { "0" => { "dir" => "asc", "name" => "only_sort" } }
Expand Down Expand Up @@ -382,6 +392,10 @@ def self.simple_escaping?
it { should include 'only_search' }
it { should_not include 'only_sort' }
it { should_not include 'only_admin' }

if Ransack::SUPPORTS_ATTRIBUTE_ALIAS
it { should include 'full_name' }
end
end

context 'with auth_object :admin' do
Expand Down
11 changes: 11 additions & 0 deletions spec/ransack/search_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ module Ransack
expect(condition.value).to eq 'Ernie'
end

if Ransack::SUPPORTS_ATTRIBUTE_ALIAS
it 'creates conditions for aliased attributes' do
search = Search.new(Person, full_name_eq: 'Ernie')
condition = search.base[:full_name_eq]
expect(condition).to be_a Nodes::Condition
expect(condition.predicate.name).to eq 'eq'
expect(condition.attributes.first.name).to eq 'full_name'
expect(condition.value).to eq 'Ernie'
end
end

it 'preserves default scope and conditions for associations' do
search = Search.new(Person, published_articles_title_eq: 'Test')
expect(search.result.to_sql).to include 'default_scope'
Expand Down
6 changes: 4 additions & 2 deletions spec/support/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class Person < ActiveRecord::Base
of_age ? where("age >= ?", 18) : where("age < ?", 18)
}

alias_attribute :full_name, :name

ransacker :reversed_name, :formatter => proc { |v| v.reverse } do |parent|
parent.table[:name]
end
Expand Down Expand Up @@ -89,9 +91,9 @@ class Person < ActiveRecord::Base

def self.ransackable_attributes(auth_object = nil)
if auth_object == :admin
column_names + _ransackers.keys - ['only_sort']
super - ['only_sort']
else
column_names + _ransackers.keys - ['only_sort', 'only_admin']
super - ['only_sort', 'only_admin']
end
end

Expand Down