Могу ли я рассчитывать на основе виртуального атрибута?
У меня есть следующая ошибка:
no such column: company_name: SELECT count("contact_emails".id) AS count_id FROM "contact_emails"
Модель ContactEmail НЕ имеет столбца company_name. Я создал его как виртуальный атрибут.
Невозможно сделать выбор на основе этой информации? Как мне тогда это сделать?
ContactEmail принадлежит_ к контакту, который принадлежит_ к компании.
1 ответ
Виртуальные атрибуты, добавленные в определение класса, но не представленные в базе данных, не могут использоваться для выбора базы данных, поскольку виртуальный атрибут отсутствует в базе данных.
Вы можете использовать базу данных для выбора надмножества нужных строк, а затем сделать второй выбор на уровне Rails, который будет использовать виртуальный атрибут.
Например
# model Citizen class file
# model fields:
# id
# name
# age
# city
def can_vote? # a virtual attribute
age >= 18
end
def self.find_voters_by_city(city) # class level finder
# returns array of voters in a city
citizens = Citizen.find_by_city(city) # First select done in database
citizens.select{|citizen| citizen.can_vote?} # Second select is done at Rails
# level using the Array#select
# method
end
Обратите внимание, что хотя вышеприведенное работает нормально, вы должны быть очень осторожны в отношении проблем с производительностью. Выбор на уровне Rails намного медленнее, чем выбор в БД. Кроме того, вы передаете гораздо больше данных через соединение Rails / СУБД, чем было бы необходимо в противном случае.
Если вы собираетесь что-то выбирать на регулярной основе, то обычно лучше поместить виртуальный атрибут в базу данных - сделать его реальным атрибутом в базе данных.
Если ваша таблица не может быть изменена, вы также можете создать вторую таблицу с отношением has_one. Вторая таблица будет содержать дополнительные атрибуты.
Добавлено: выбор в базе данных с использованием двух таблиц
### model Contact
# id
# name
# city
has_one :company
def company_name; company.name; end # a virtual attribute
### model Company
# id
# contact_id
# name
# employee_count
belongs_to :contact
### Selecting on city (from Contact) and employee_count (from Company)
city = xyz # the city we are searching for
employee_count = 123 # minimum company size we want
contacts = Contact.find(:all,
:conditions => ["contacts.city = ? and companies.employee_count >= ?",
city, employee_count],
:include => :company)
# above statement does the join and select in the database
# There are also techniques involving named scopes for the above
# And in Rails 3, it will be different too.