Несколько ассоциаций к той же модели

У меня есть два класса, которые я хотел бы указать следующим образом:

class Club < ActiveRecord::Base
  belongs_to :president, :class_name => "Person", :foreign_key => "president_id"
  belongs_to :vice_president, 
             :class_name => "Person",
             :foreign_key => "vice_president_id"
end

class Person < ActiveRecord::Base
  has_one :club, :conditions => 
  ['president_id = ? OR vice_president_id = ?', '#{self.id}', '#{self.id}']
end

Это не работает и дает мне ошибку при попытке получить ассоциацию клуба от объекта человека. Ошибка состоит в том, потому что ищет person_id в таблице клуба, когда я посмотрел на SQL. Я могу обойти его путем объявления нескольких has_one ассоциаций, но чувствовать, что это - неподходящий способ сделать его.

Человек может только быть президентом или вице-президентом одного клуба.

Любой, который в состоянии дать определенный совет относительно этой проблемы, я был бы очень благодарен.

6
задан adimitri 8 February 2010 в 08:23
поделиться

4 ответа

Насколько я знаю, ваше условие has_one никогда не будет работать в Rails.

Вам нужен один явный has_one или own_to или has_many для каждой «ссылки» в обеих таблицах. Итак, если у вас есть две «ссылки», вам понадобятся две has_one и две own_to . Вот как это работает.

Во-вторых, я думаю, вам следует пересмотреть свои модели. Как вы это делаете, один человек не может быть президентом клуба и сотрудником одновременно. Или быть президентом двух клубов. Даже если у вас их нет прямо сейчас, они могут появиться в будущем - сейчас проще оставаться гибким.

Гибкий способ сделать это - использовать has_many: через с промежуточной таблицей, определяющей роль. Другими словами:

# The memberships table has a person_id, club_id and role_id, all integers

class Membership < ActiveRecord::Base
  belongs_to :club
  belongs_to :person
  validates_presence_of :role_id
  validates_numericality_of :role_id
end

class Club < ActiveRecord::Base
  has_many :memberships, :dependent => :delete_all
  has_many :people, :through => :memberships
end

class Person < ActiveRecord::Base
  has_many :memberships, :dependent => :delete_all
  has_many :clubs, :through => :memberships
end

Теперь, предполагая, что role_id = 0 означает сотрудника, role_id = 1 означает президента, а role_id = 2 означает Vice_president, вы можете использовать это так:

tyler = Person.find(1) # person_id is 1
other = Person.find(2) # person_id is 2
c = Club.find(1)  # club_id is 1

tyler.clubs # returns all the clubs this person is "member" of
c.people # returns all the "members" of this club, no matter their role

#make tyler the president of c
tyler.memberships.create(:club_id => 1, :role_id => 1)

#make other the vicepresident of c
#but using c.memberships instead of other.memberships (works both ways)
c.memberships.create(:person_id => 2, :role_id => 1)

#find the (first) president of c
c.memberships.find_by_role_id(1).person

#find the (first) vicepresident of c
c.memberships.find_by_role_id(2).person

#find all the employees of c
c.memberships.find_all_by_role_id(0).collect { |m| m.person }

#find all the clubs of which tyler is president
tyler.memberships.find_all_by_role_id(1).collect { |m| m.club }

Дополнительные примечания:

  • Вы можете дополнить это с таблицей ролей и моделью. Роли будут иметь только имя, роли будут иметь отношения have_many , а членство - роль own_to .Или вы можете определить методы в членстве для получения имени роли (если 0, возвращается «сотрудник», если 1, «президент» и т. Д.
  • Вы можете добавить проверки членства, чтобы президентом можно было сделать не более 1 человека. одного и того же клуба или один и тот же сотрудник в одном клубе дважды. Позже, если вы начнете получать «исключительные случаи», когда человек должен находиться в двух местах, вам просто нужно будет адаптировать свои проверки.
8
ответ дан 16 December 2019 в 21:39
поделиться

Рекомендуется использовать Boost.Regex .

Пример (с веб-сайта):

bool validate_card_format(const std::string& s)
{
   static const boost::regex e("(\\d{4}[- ]){3}\\d{4}");
   return regex_match(s, e);
}

Другой пример:

// match any format with the regular expression:
const boost::regex e("\\A(\\d{3,4})[- ]?(\\d{4})[- ]?(\\d{4})[- ]?(\\d{4})\\z");
const std::string machine_format("\\1\\2\\3\\4");
const std::string human_format("\\1-\\2-\\3-\\4");

std::string machine_readable_card_number(const std::string s)
{
   return regex_replace(s, e, machine_format, boost::match_default | boost::format_sed);
}

std::string human_readable_card_number(const std::string s)
{
   return regex_replace(s, e, human_format, boost::match_default | boost::format_sed);
}
-121--3090652-

Для хранения изображений я всегда хранил их на жестком диске, но используя очень жесткий сценарий проверки изображений, чтобы убедиться, что изображения не содержат вредоносного кода. Я также используется для применения перезаписи URL, чтобы пользователи не могли найти реальный путь к изображениям.

Разве у вас нет странного ощущения, что вы храните изображения в базах данных? База данных mysql может расти очень быстро, и вам всегда нужен PHP скрипт для отображения изображений, что означает, что это делает ваш сервер медленнее.


Что касается места хранения пароля, используйте соление, как ответили другие.


Наконец, для документации, я очень люблю видеть, как Wordpress структурирован. Я часами смотрел исходный код и читал документы. Это просто ужасно хороший пример того, как организовать любой сайт.

-121--4903885-

Это классический пример использования полиморфных ассоциаций. Вот ссылка: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Что-то вроде..

class Club < ActiveRecord::Base
  belongs_to :person, :polymorphic => true 

class Person < ActiveRecord::Base
  has_one :club, :as => :position
0
ответ дан 16 December 2019 в 21:39
поделиться

Я думаю, что ваши ассоциации неверны . По-вашему, сложно назначить президента или вице-президента.

Я бы сделал это так:

class Club < ActiveRecord::Base
  has_one :president, 
          :class_name => "Person",
          :foreign_key => 'president_club_id'
  has_one :vice_president, 
          :class_name => "Person", 
          :foreign_key => 'vice_president_club_id'
end

class Person < ActiveRecord::Base
  belongs_to :club
end

Теперь вы можете назначать роли так:

club.president = Person.create(:name => 'Tom')
club.vice_president = Person.create(:name => 'Andrew')
0
ответ дан 16 December 2019 в 21:39
поделиться

Предлагаю вам представить новую модель, которая называется ролью. Затем получите следующее:

class Club
  has_many :roles 

  def president
  end

  def vice_president
  end

end

class Person
  belongs_to :role
end

class Role
  has_one :person
  belongs_to :club
end
0
ответ дан 16 December 2019 в 21:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: