Отчасти я люблю Rails в том, что я ненавижу SQL - я думаю, что это больше похоже на язык ассемблера, которым нужно манипулировать с помощью инструментов более высокого уровня, таких как ActiveRecord. Однако я, кажется, перешел границы этого подхода, и я не в себе с SQL.
У меня сложная модель с множеством вложенных записей. У меня также есть набор 30-40 named_scopes, которые реализуют бизнес-логику от клиента. Эти области видимости соединяются вместе условно, поэтому у меня есть эти joins_
области видимости, чтобы соединения не были засорены.
У меня есть пара из них, которые работают неправильно, или, по крайней мере, не так, как клиент хочет, чтобы они работали. Вот примерное представление о структуре модели с несколькими именованными областями (не все, что нужно для примера), которые иллюстрируют мой подход и указывают на мои проблемы. (прошу прощения за любые синтаксические ошибки)
class Man < ActiveRecord::Base
has_many :wives
named_scope :has_wife_named lambda { |n| { :conditions => { :wives => {:name => n}}}}
named_scope :has_young_wife_named lambda { |n| { :conditions => { :wives => {:name => n, :age => 0..30}}}}
named_scope :has_yw_named_v2 lambda { |n| { :conditions => ["wives.name = ? AND wives.age <= 30", n]}}
named_scope :joins_wives :joins => :wives
named_scope :has_red_cat :conditions => { :cats => {:color => 'red'}}
named_scope :has_cat_of_color lambda { |c| { :conditions => { :cats => {:color => c}}}}
named_scope :has_7yo_cat :conditions => { :cats => {:age => 7}}
named_scope :has_cat_of_age lambda { |a| { :conditions => { :cats => {:age => a}}}}
named_scope :has_cat_older_than lambda { |a| { :conditions => ["cats.age > ?", a] }}
named_scope :has_cat_younger_than lambda { |a| { :conditions => ["cats.age < ?", a] }}
named_scope :has_cat_fatter_than lambda { |w| { :conditions => ["cats.weight > ?", w] } }
named_scope :joins_wives_cats :joins => {:wives => :cats}
end
class Wife < ActiveRecord::Base
belongs_to :man
has_many :cats
end
class Cat < ActiveRecord::Base
belongs_to :wife
end
Я могу найти мужчин, чьи жены имеют рыжих кошек И семи лет
@men = Man.has_red_cat.has_7yo_cat.joins_wives_cats.scoped({:select => 'DISTINCT men'})
И я даже могу найти мужчин, у жен которых есть кошки весом более 20 фунтов и старше 6 лет
@men = Man.has_cat_fatter_than(20).has_cat_older_than(5).joins_wives_cats.scoped({:select => 'DISTINCT men'})
Но это не то, что я хочу. Я хочу найти мужчин, чьи жены имеют по крайней мере одну рыжую кошку и одну семилетнюю кошку, которые не обязательно должны быть одной и той же кошкой, или найти мужчин, чьи жены имеют по крайней мере одну кошку выше заданного веса и одна кошка старше данного возраста.
(в последующих примерах, пожалуйста, предположите наличие соответствующих joins_
и DISTINCT
)
Я могу найти мужчин с женами по имени Эстер
@men = Man.has_wife_named('Esther')
Я даже могу найти мужчин с женами по имени Эстер, Руфь ИЛИ Ада (сладкая!)
@men = Man.has_wife_named(['Esther', 'Ruth', 'Ada'])
но я хочу найти мужчин с женами по имени Эстер, Руфь и Ада.
Ха-ха, только шучу, на самом деле, мне это нужно: я могу найти мужчин с женами до 30 лет по имени Эстер
@men = Man.has_young_wife_named('Esther')
найти мужчин с молодыми женами по имени Эстер, Руфь или Ада
@men = Man.has_young_wife_named(['Esther', 'Ruth', 'Ada'])
но, как и выше, я хочу найти мужчин с молодыми женами по имени Эстер, Руфь и Ада. К счастью, в этом случае зафиксирован минимум, но было бы неплохо указать и минимальный возраст.
есть ли способ проверить неравенство с хэш-синтаксисом, или вам всегда приходится возвращаться к :conditions => ["", n]
- обратите внимание на разницу между has_young_wife_named
и has_yw_named_v2
- мне больше нравится первое, но диапазон работает только для конечных значений. Если вы ищете старую жену, я думаю, вы могли бы использовать a..100
, но затем, когда жене исполняется 101 год, она прекращает поиск. (хм. Она умеет готовить? Дж / к)
есть ли способ использовать область в пределах области? Мне бы понравилось, если бы :has_red_cat
мог каким-то образом использовать :has_cat_of_color
, или если бы был какой-то способ использовать область из дочерней записи в ее родительском элементе, чтобы я мог поместить связанные с кошкой области в модель Wife
.
Я действительно не хочу делать это в прямом SQL без использования named_scope
, если только нет чего-то действительно более приятного - предложения по плагинам и тому подобное, которые не очень ценятся, или указание на тот тип SQL, который мне нужно изучить. Один мой друг предположил, что UNION или подиски будут работать здесь, но, похоже, они мало обсуждаются в контексте Rails. Я пока ничего не знаю о взглядах - они будут полезны? Есть ли способ сделать их счастливыми с помощью рельсов?
Спасибо!
Как я собирался в Сент-Айвс
Я встретил мужчину с семью женами
У каждой жены было семь мешков
В каждом мешке было по семь кошек
У каждой кошки было семь наборов
Комплекты, кошки, мешки, жены
Сколько собирались в Сент-Айвс?