开发者

Remove a 'where' clause from an ActiveRecord::Relation

开发者 https://www.devze.com 2023-03-12 07:30 出处:网络
I have a class method on User, that returns appl开发者_如何转开发ies a complicated select / join / order / limit to User, and returns the relation. It also applies a where(:admin => true) clause. I

I have a class method on User, that returns appl开发者_如何转开发ies a complicated select / join / order / limit to User, and returns the relation. It also applies a where(:admin => true) clause. Is it possible to remove this one particular where statement, if I have that relation object with me?

Something like

User.complex_stuff.without_where(:admin => true)


I know this is an old question, but since rails 4 now you can do this

User.complex_stuff.unscope(where: :admin)

This will remove the where admin part of the query, if you want to unscope the whole where part unconditinoally

User.complex_stuff.unscope(:where)

ps: thanks to @Samuel for pointing out my mistake


I haven't found a way to do this. The best solution is probably to restructure your existing complex_stuff method.

First, create a new method complex_stuff_without_admin that does everything complex_stuff does except for adding the where(:admin => true). Then rewrite the complex_stuff method to call User.complex_stuff_without_admin.where(:admin => true).

Basically, just approach it from the opposite side. Add where needed, rather than taking away where not needed.


This is an old question and this doesn't answer the question per say but rewhere is a thing that exists.

From the documentation:

Allows you to change a previously set where condition for a given attribute, instead of appending to that condition.

So something like:

Person.where(name: "John Smith", status: "live").rewhere(name: "DickieBoy")

Will output:

SELECT `people`.* FROM `people` WHERE `people`.`name` = 'DickieBoy' AND `people`.`status` = 'live';

The key point being that the name column has been overwritten, but the status column has stayed.


You could do something like this (where_values holds each where query; you'd have to tweak the SQL to match the exact output of :admin => true on your system). Keep in mind this will only work if you haven't actually executed the query yet (i.e. you haven't called .all on it, or used its results in a view):

@users = User.complex_stuff
@users.where_values.delete_if { |query| query.to_sql == "\"users\".\"admin\" = 't'" }

However, I'd strongly recommend using Emily's answer of restructuring the complex_stuff method instead.


I needed to do this (Remove a 'where' clause from an ActiveRecord::Relation which was being created by a scope) while joining two scopes, and did it like this: self.scope(from,to).values[:joins].

I wanted to join values from the two scopes that made up the 'joined_scope' without the 'where' clauses, so that I could add altered 'where' clauses separately (altered to use 'OR' instead of 'AND').

For me, this went in the joined scope, like so:

scope :joined_scope, -> (from, to) {
  joins(self.first_scope(from,to).values[:joins])
  .joins(self.other_scope(from,to).values[:joins])
  .where(first_scope(from,to).ast.cores.last.wheres.inject{|ws, w| (ws &&= ws.and(w)) || w}
  .or(other_scope(from,to).ast.cores.last.wheres.last))
}

Hope that helps someone

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号