简体   繁体   中英

Ransacker predicate for multiple associations

I have a case where I have a model called Event which: * has_one primary_day * has_one backup_day * has_one emergency_day

In each of the has_one associations there a group of boolean fields that are the same eg approved_legal,approved_malfunction,approved_costs etc

In my search form - I don't want to search each association individually for those same fields.

eg I don't want to do this:

<%= f.check_box :primary_day_approved_legal_true %>

for each of the fields as it's too verbose instead I want to do this:

<%= f.check_box :approved_legal_true %> 

which will collate all the associations and return Events that have approved_legal true across all the has_one associations.

I have tried a few different approaches to solving this but I can't get it to work so I assume that what I want to do is currently not possible. Could you confirm my theory or let me know how it could be achieved if it is indeed possible?

For reference I have tried the following:

1. custom ransacker in the Event model

Since I'm happy to use the existing true predicate I thought just adding in a ransacker that returned what I wanted would be possible. But it seems not eg

ransacker :created_at do |parent|
  Arel.sql('select * from events inner join on primary_days .......')
end

this ransacker seems to alway start with a select on the Model it was added to. So I cannot use a join to the associations. It seems the ransacker must return an existing database column on the model it's related to. So for the same reason there was not Arel code I could come up with that would make this approach work. Despite trying to create an Arel table to represent the associations and then trying to do the join in arel - but the result was always the same - no such method eq on ArelSelectManager.

eg

ransacker :created_at do |parent|
  primary_days = Arel::Table.new(:primary_days)
  events = parent.table
  events.join(primary_days).on(events[:id].eq(primary_days[:event_id]))
end

2. Using a named scope with a patch for scopes found in issue 61 - https://gist.github.com/RohanM/5350768

I put the code in the initializers/ransack.rb and then:

Model:

scope_ransackable :approved_legal
scope :approved_legal_scope, -> { 
  Event.joins(:primary_day).where(:primary_days: {approved_legal: true}) 
}

Controller

Event.search_with_scopes(params[q])

View

<%= f.check_box(:approved_legal_scope)%>

But this just resulted in an error saying that approved_legal_scope method was not found on Ransack Search object

Any pointer in the right direction would be very much appreciated. Thanks.

I have managed to achieve this with chaining scopes with a pre-Rails 5 hack.

scope :short_search_scope, ->(search) {
   joins(:something)
  .where(
    unscoped.one_scope(search)
     .another_scope(search)
     .where_values.join(' OR '))
}

scope :one_scope, -> (search) {
  where(approved_legal: true)
}

...

def self.ransackable_scopes(auth_object = nil)
  [:short_search_scope]
end

The where_values.join(' OR ') can be replaced with where().or.where() when this feature is released in Rails 5.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM