2013-03-04 2 views
0

Я новичок в рельсах и пытаюсь понять, как делать ассоциации, и если я сделал это правильно. Я читал rails guide on associations и искал в Интернете и нашел несколько ресурсов, но я просто не уверен.Simple Rails 3 Association - has_many, принадлежит_to, и has_and_belongs_to_many

Вы можете увидеть мой проект здесь: majorfinder.com В моем приложении будут специальности, школы и карьера. Я хочу иметь возможность добавлять отзывы для каждого. Поскольку я только начинаю, я только начинаю с добавления отзывов для майоров.

Вот мои ассоциации:

модели/review.rb

belongs_to :user 
has_and_belongs_to_many :majors 

модели/user.rb

has_many :reviews 

модели/major.rb

has_and_belongs_to_many :reviews 

Мои первый вопрос есть, делает это как хороший способ создать ассоциации?

Я понимаю, как сделать простую ассоциацию в контроллере Специальности:

@reviews = Review.includes(:user) 

и что я могу показать отзыв мой главный контроллер:

<div class="row"> 
    <% @reviews.each do |review| %> 
    <div> 
     <h3><%= link_to review.review, 
     :controller => "reviews", :action => "show", :id => review.id %></h3> 
     <small>Posted on <%= review.created_at %> by 
     <a href="#"><%= review.user.profile_name %></a></small> 
    </div> 
    <% end %> 
</div> 

, но я не знаю, как чтобы связать это с конкретным майором, на который я смотрю.

В моей схеме базы данных обзора есть обзор (текст), user_id (целое число) и major_id (целое число).

Последний вопрос: как я могу опубликовать обзор на главной странице просмотра контроллера с этим конкретным майне, связанным с ним?

ответ

1

Во-первых, вы уверены, что хотите has_and_belongs_to_many между reviews и majors? Я бы предположил, что каждый обзор относится только к одной конкретной специальности (или к школе/карьере), если это так, это отношения «один ко многим», и вы захотите использовать has_many и belongs_to.

Во-вторых, учитывая, что в конечном итоге вы захотите добавить отзывы к другим моделям, вы можете сделать это polymorphic association, что позволит вам использовать ту же модель review для всех трех других моделей. Чтобы сделать это, вы хотите изменить свои ассоциации к следующему:

# In review.rb 
belongs_to :reviewable, polymorphic: true 

# In major.rb (and later also in school.rb and career.rb) 
has_many :reviews, as: :reviewable 

Вам также нужно изменить модель обзора, то так, что вместо того, чтобы иметь major_id свойство, она имеет reviewable_idinteger собственности и reviewable_typestring Недвижимость.

С точки зрения того, как вы хотите их отображать, вы, вероятно, захотите включить модели review и user при первоначальной загрузке основного (при условии, что вы хотите показать все отзывы, хотя в конечном итоге вы можете захотеть посмотреть на разделив их на страницах, если есть их много):

# In majors_controller.rb (or whatever it's named) 
def show 
    @major = Major.includes(:reviews => :user).find(params[:id]) 
    ... 

Затем на ваш взгляд, вы можете пользователя по reviews метод @major доступа к ним (помните, что ассоциации также add a bunch of methods к моделям, чтобы сделать их проще в использовании)

# In /app/views/majors/show.html.erb 
<div class="row"> 
    <% @major.reviews.each do |review| %> 
    ... 
    <% end %> 
</div> 

Или более удобно, можно использовать частичный (если вы хотите, чтобы отобразить список обзоров таким же образом, на каждой странице), и использовать ярлык для рендеринга коллекции:

# /app/views/reviews/_review.html.erb 
<div> 
    <h3><%= link_to review.review, 
    :controller => "reviews", :action => "show", :id => review.id %></h3> 
    <small>Posted on <%= review.created_at %> by 
    <a href="#"><%= review.user.profile_name %></a></small> 
</div> 

# In /app/views/majors/show.html.erb 
<div class="row"> 
    <%= render @major.reviews %> 
</div> 
+0

Большое спасибо Заиду! Это так полезно! Я встречаю одну ошибку: NoMethodError в MajorsController # show undefined method 'includes 'для # , В моем файле majors_controller.rb, хотя у меня есть: def show @major = Major.find_by_slug (params [: id]). включает (: отзывы =>: пользователь) end – lflores

+1

Это было мое плохое, '.includes()' должно появиться перед '.find()', поэтому '@major = Major.includes (: reviews =>: user) .find_by_slug (params [: id]) 'должен работать. –

+0

Это, спасибо! – lflores

0

С уважением для того, являются ли они соответствующими ассоциациями, все зависит от того, чего вы пытаетесь достичь, и от того, что отношения действительно выглядят в «реальном» мире.

С его помощью у вас есть пользователи, которые могут создавать (или иметь) разные отзывы, у вас есть майоры, где каждый отдельный майор может иметь множество отзывов, связанных с ним, и у вас есть обзоры, где каждый отдельный обзор связан со многими различными специалистами (т. е. один обзор может быть написан о нескольких разных специализациях).

Это правильно? Если это так, то ассоциации, которые вы пытаетесь создать, кажутся уместными.

Однако я не уверен, что вы вполне там с реализацией.

Отзыв принадлежит пользователю, и поэтому уместно, чтобы у него был столбец user_id, однако он не должен иметь столбец major_id (в противном случае вы ограничиваете каждый отзыв принадлежащим только одному крупному).

Вместо этого отношения между майорами и рецензиями управляются через таблицу объединений (например, major_reviews), которая затем имеет столбцы major_id и review_id. Вы уже создали эту таблицу соединений?

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

Например, чтобы получить все отзывы данного пользователя, вы можете сделать @user.reviews. Аналогично, чтобы получить соответствующие специальности для отдельного обзора, вы можете сделать @review.majors, или получить все отзывы для данного крупного специалиста, вы можете сделать @major.reviews.

Дополнительные примеры способов, доступных для @major или @review, приведены в разделе 4.4.1 руководства Rails http://guides.rubyonrails.org/association_basics.html#the-has_and_belongs_to_many-association.

+0

Я действительно хочу, чтобы каждый обзор касался только одного майора. Похоже, я мог правильно настроить его. Спасибо!! – lflores

+0

В этом случае has_and_belongs_to_many, вероятно, не подходит, и, как упоминает Zaid ниже, вам будет лучше использовать has_many и принадлежит для отношений между майорами и отзывами. Ваша схема базы данных уже настроена для этого, но вам нужно будет внести изменения в модели. – simonb83

Смежные вопросы