Ik gebruik Rails3, ActiveRecord
Ik vraag me alleen af hoe ik de scopes kan koppelen aan OR-statements in plaats van AND.
bijv.
Person.where(:name => "John").where(:lastname => "Smith")
Dat keert normaal gesproken terug:
name = 'John' AND lastname = 'Smith'
maar ik wil graag:
`name = 'John' OR lastname = 'Smith'
Antwoord 1, autoriteit 100%
Je zou doen
Person.where('name=? OR lastname=?', 'John', 'Smith')
Op dit moment is er geen andere OF-ondersteuning door de nieuwe AR3-syntaxis (dat wil zeggen zonder een juweeltje van derden te gebruiken).
Antwoord 2, autoriteit 67%
Volgens dit pull-verzoekondersteunt Rails 5 nu de volgende syntaxis voor het koppelen van query’s :
Post.where(id: 1).or(Post.where(id: 2))
Er is ook een backport van de functionaliteit in Rails 4.2 via dit juweeltje.
Antwoord 3, autoriteit 47%
Gewoon de array-syntaxis posten voor dezelfdekolom OF zoekopdrachten om te kijken hoe het eruit ziet.
Person.where(name: ["John", "Steve"])
Antwoord 4, autoriteit 44%
Gebruik ARel
t = Person.arel_table
results = Person.where(
t[:name].eq("John").
or(t[:lastname].eq("Smith"))
)
Antwoord 5, autoriteit 34%
Update voor Rails4
vereist geen edelstenen van derden
a = Person.where(name: "John") # or any scope
b = Person.where(lastname: "Smith") # or any scope
Person.where([a, b].map{|s| s.arel.constraints.reduce(:and) }.reduce(:or))\
.tap {|sc| sc.bind_values = [a, b].map(&:bind_values) }
Oud antwoord
vereist geen edelstenen van derden
Person.where(
Person.where(:name => "John").where(:lastname => "Smith")
.where_values.reduce(:or)
)
Antwoord 6, autoriteit 21%
In het geval dat iemand op zoek is naar een bijgewerkt antwoord hierop, het lijkt erop dat er een bestaand pull-verzoek is om dit in Rails te krijgen: https://github.com/rails/rails/pull/9052.
Dankzij @j-mcnally’s Monkey patch voor ActiveRecord (https://gist.github.com/j-mcnally/ 250eaaceef234dd8971b) kunt u het volgende doen:
Person.where(name: 'John').or.where(last_name: 'Smith').all
Nog waardevoller is de mogelijkheid om scopes te koppelen met OR
:
scope :first_or_last_name, ->(name) { where(name: name.split(' ').first).or.where(last_name: name.split(' ').last) }
scope :parent_last_name, ->(name) { includes(:parents).where(last_name: name) }
Dan kun je alle personen vinden met voor- of achternaam of wiens ouder met achternaam
Person.first_or_last_name('John Smith').or.parent_last_name('Smith')
Niet het beste voorbeeld om dit te gebruiken, maar probeer het gewoon bij de vraag te passen.
7, Autoriteit 2%
Zie ook deze gerelateerde vragen: hier, hieren hier
Voor rails 4, gebaseerd op dit artikelen dit originele antwoord
Person
.unscoped # See the caution note below. Maybe you want default scope here, in which case just remove this line.
.where( # Begin a where clause
where(:name => "John").where(:lastname => "Smith") # join the scopes to be OR'd
.where_values # get an array of arel where clause conditions based on the chain thus far
.inject(:or) # inject the OR operator into the arels
# ^^ Inject may not work in Rails3. But this should work instead:
.joins(" OR ")
# ^^ Remember to only use .inject or .joins, not both
) # Resurface the arels inside the overarching query
Let opde waarschuwing van het artikel aan het einde:
Rails 4.1+
Rails 4.1 behandelt default_scope net als een gewone scope. De standaard
scope (als je die hebt) is opgenomen in het where_values resultaat en
inject(:or) zal een statement toevoegen tussen het standaardbereik en uw
waar is. Dat is slecht.Om dat op te lossen, hoeft u alleen het bereik van de zoekopdracht uit te schakelen.
Antwoord 8, autoriteit 2%
Dit is een erg handige manier en het werkt prima in Rails 5:
Transaction
.where(transaction_type: ["Create", "Correspond"])
.or(
Transaction.where(
transaction_type: "Status",
field: "Status",
newvalue: ["resolved", "deleted"]
)
)
.or(
Transaction.where(transaction_type: "Set", field: "Queue")
)
Antwoord 9
de squeel
-edelsteen biedt een ongelooflijk gemakkelijke manier om dit te bereiken (voorheen gebruikte ik zoiets als de methode van @coloradoblue):
names = ["Kroger", "Walmart", "Target", "Aldi"]
matching_stores = Grocery.where{name.like_any(names)}
Antwoord 10
Dus het antwoord op de oorspronkelijke vraag, kun je scopes samenvoegen met ‘of’ in plaats van ‘en’ lijkt te zijn ‘nee, dat kan niet’. Maar u kunt een geheel andere scope of query met de hand coderen die het werk doet, of een ander framework gebruiken dan ActiveRecord, b.v. Meta Where of Squeel. Niet nuttig in mijn geval
Ik gebruik een bereik dat is gegenereerd door pg_search, dat iets meer doet dan selecteren, het bevat een bestelling door ASC, wat een puinhoop maakt van een schone unie. Ik wil het ‘of’ met een handgemaakte scope die dingen doet die ik niet kan doen in pg_search. Dus ik heb het zo moeten doen.
Product.find_by_sql("(#{Product.code_starts_with('Tom').to_sql}) union (#{Product.name_starts_with('Tom').to_sql})")
D.w.z. verander de scopes in sql, plaats haakjes om elke scope, voeg ze samen en find_by_sql met behulp van de gegenereerde sql. Het is een beetje onzin, maar het werkt wel.
Nee, vertel me niet dat ik “tegen: [:name,:code]” kan gebruiken in pg_search, ik zou het zo willen doen, maar het veld ‘name’ is een hstore, wat pg_search kan nog niet aan. Dus het bereik op naam moet met de hand worden gemaakt en vervolgens worden samengevoegd met het bereik pg_search.
Antwoord 11
Ik werk nu in Rails 6 en het lijkt erop dat dit nu mogelijk is. Met behulp van de vragen van de OP:
# in the Person model:
scope :john, -> { where(name: "John") }
scope :smith, -> { where(lastname: "Smith") }
scope :john_or_smith, -> { john.or(self.smith) }
Antwoord 12
names = ["tim", "tom", "bob", "alex"]
sql_string = names.map { |t| "name = '#{t}'" }.join(" OR ")
@people = People.where(sql_string)