0

В нашем приложении Rails, есть 3 модели:Рельсы has_many: через ассоциацию: получить иностранный атрибут через внешний ключ

class User < ActiveRecord::Base 
    has_many :administrations, dependent: :destroy 
    has_many :calendars, through: :administrations 
end 

class Administration < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :calendar 
end 

class Calendar < ActiveRecord::Base 
    has_many :administrations, dependent: :destroy 
    has_many :users, through: :administrations 
end 

А вот соответствующие Миграции:

class CreateUsers < ActiveRecord::Migration 
    def change 
    create_table :users do |t| 
     t.string :first_name 
     t.string :last_name 
     t.string :email 

     t.timestamps null: false 
    end 
    end 
end 

class CreateAdministrations < ActiveRecord::Migration 
    def change 
    create_table :administrations do |t| 
     t.references :user, index: true, foreign_key: true 
     t.references :calendar, index: true, foreign_key: true 
     t.string :role 

     t.timestamps null: false 
    end 
    end 
end 

class CreateCalendars < ActiveRecord::Migration 
    def change 
    create_table :calendars do |t| 
     t.string :name 

     t.timestamps null: false 
    end 
    end 
end 

EDIT: здесь также наш UsersController:

class UsersController < ApplicationController 
    before_action :logged_in_user, only: [:edit, :update, :destroy] 
    before_action :correct_user, only: [:edit, :update] 
    before_action :admin_user,  only: [:index, :destroy] 

    def index 
    @users = User.paginate(page: params[:page], :per_page => 10) 
    end 

    def show 
    @user = User.find(params[:id]) 
    @administrations = @user.administrations 
    @calendar = current_user.calendars.build if logged_in? 
    end 

    def new 
    @user = User.new 
    end 

    def create 
    @user = User.new(user_params) 
    if @user.save 
     @user.send_activation_email 
     flash[:info] = "Please check your email to activate your account." 
     redirect_to root_url 
    else 
     render 'new' 
    end 
    end 

    def edit 
    @user = User.find(params[:id]) 
    end 

    def update 
    @user = User.find(params[:id]) 
    if @user.update_attributes(user_params) 
     flash[:success] = "Profile updated" 
     redirect_to @user 
    else 
     render 'edit' 
    end 
    end 

    def destroy 
    User.find(params[:id]).destroy 
    flash[:success] = "User deleted" 
    redirect_to users_url 
    end 

    private 

    def user_params 
     params.require(:user).permit(:first_name, :last_name, :email, 
            :password, :password_confirmation) 
    end 

    # Before filters 

    # Confirms the correct user. 
    def correct_user 
     @user = User.find(params[:id]) 
     redirect_to(root_url) unless current_user?(@user) 
    end 

    # Confirms an admin user. 
    def admin_user 
     redirect_to(root_url) unless current_user.try(:admin?) 
    end 

end 

Как только пользователь войдет в систему (система аутентификации уже запущена и работает), мы хотим отобразить в его профиле (пользователи # show) все созданные календари.

Мы посеяли базу данных с помощью следующих случаях:

User.create!(first_name: "Andy") # This user's id is 1. 

Calendar.create!(name: "CalendarA") 

Calendar.create!(name: "CalendarB") 

Calendar.create!(name: "CalendarC") 

Administration.create!(user_id: 1, calendar_id: 1, role: "Creator") 

Administration.create!(user_id: 1, calendar_id: 2, role: "Editor") 

Administration.create!(user_id: 1, calendar_id: 3, role: "Viewer") 

Затем мы создали _administration.html.erb парциальное:

<li id="administration-<%= administration.id %>"> 
    <span class="name"><%= administration.calendar_id %></span> 
</li> 

И включили его в наш пользователь show.html.erb файл:

<p><%= @user.first_name %>'s calendars</p> 
<% if @user.administrations.any? %> 
<%= render @administrations %> 
<% end %> 

И это работает, мы получаем:

Andy's calendars:

  • 1
  • 2
  • 3

Однако то, что мы хотели бы получить для каждого пользователя, не только id s из своих календарей, но их name слишком, как это:

Andy's calendars:

  • 1 CalendarA
  • 2 CalendarB
  • 3 CalendarC

Таким образом, мы попытались обновить _administration.html.erb парциальное следующим образом:

<li id="administration-<%= administration.id %>"> 
    <span class="name"><%= administration.calendar_id.name %></span> 
</li> 

что приводит к следующей ошибке:

NoMethodError in UsersController#show 

undefined method `name' for 1:Fixnum 

Application Trace | Framework Trace | Full Trace 
app/views/administrations/_administration.html.erb:2:in `_app_views_administrations__administration_html_erb__2225316747000531998_70329866860100' 
app/views/users/show.html.erb:32:in `_app_views_users_show_html_erb___891585127045041471_70329832995240' 

Как мы можем получить доступ к «чужой» атрибут name из calendar модели через внешний ключ calendar_id в присоединиться administration модели?

ответ

2

administration.calendar.name должен работать, если ваши ассоциации настроены правильно.

В качестве альтернативы, вы можете добавить этот метод Administration:

def calendar_name 
    calendar.name 
end 

, а затем просто позвонить administration.calendar_name

+0

Спасибо. Ваше альтернативное решение действительно сработало. Поэтому мои ассоциации не должны быть настроены правильно. Что я должен проверить, чтобы убедиться, что они есть? –

+1

@ThibaudClement Какая ошибка возникает, если вы вызываете 'administrator.calendar.name'? – elements

+0

Это ошибка, которую мы получаем, когда мы делаем admin.calendar.name: NoMethodError в UsersController # show undefined method 'calendar 'для # . И когда мы делаем administrator.calendar_id.имя, мы получаем: NoMethodError в UsersController # show undefined method 'calendar_id 'для # <Календарь: 0x007fede22a6908> –

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