Ruby on Rails — ассоциации, модели и избранное

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

Undefined Method: 'favorites' for nil:NilClass
<h1>My Favorites</h1>

<%= @favorites = @user.favorites.to_a %>

  <table class = "favorites-table">
    <thead>

Я тестировал функциональность избранного, работая в консоли, поэтому поэкспериментировал с приведенным выше кодом в файле Favorites.html.erb.

Единственная проблема в том, что я настроил ассоциации и доказал, что могу получить доступ к этому методу через консоль rails.

u = User.first
u.favorites => nil
u.favorites.to_a << Movie.first

Это работало в ActiveRecord, но не на сервере rails.

Вот мои ассоциации (Фильм, Пользователь и Избранное)

class Movie < ActiveRecord::Base

  belongs_to :user
  has_many :favorite_movies
  has_many :favorited_by, through: :favorite_movies, source: :user
end

class User < ActiveRecord::Base

  has_many :favorites, foreign_key: "user_id", dependent: :destroy
  has_many :favorite_movies, through: :favorites, source: :movies
end

class Favorite < ActiveRecord::Base
  belongs_to :user
  validates :movie_id, presence: true
  validates :user_id, presence: true
end

Я создал эти ассоциации, прочитав главу 11 Учебника по Rails, но я не уверен, что это работает для избранных, и, возможно, я сделал пару ошибок.

Вот мои важные миграции (Фильмы, Пользователи, Избранное)

class CreateMovies < ActiveRecord::Migration
  def change
    create_table :movies do |t|
      t.string :title
      t.string :director
      t.string :genre
      t.integer :movie_id # Potential land-mine
      t.integer :release_date
      t.integer :reviewed
      t.integer :stars

    t.timestamps
    end
  end
end

Мой файл миграции пользователей

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.integer :user_id # Potential land-mine. Users already have separate ID column (primary key)
      t.string :name
      t.string :password
      t.string :email

      t.timestamps
    end
  end
end

class CreateFavorites < ActiveRecord::Migration
  def change
    create_table :favorites do |t|
      t.integer :user_id
      t.integer :movie_id

      t.timestamps
    end

    add_index :favorites, :user_id
    add_index :favorites, :movie_id
    add_index :favorites, [:user_id, :movie_id], unique: true
  end
end

Вот мои маршруты

resources :movies do
  put :favorite, on: :member
end

resources :users

У меня есть метод Favorites, определенный в моем контроллере Users, но внутри него ничего нет. Вот мой контроллер

class UsersController < ApplicationController
  before_action :signed_in_user, only: [:edit, :update, :destroy]
  before_action :correct_user, only: [:edit, :update]

  def index
    @users = User.all
  end

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

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      flash[:success] = "Congratulations #{@user.name}! You have successfully created an account"
      redirect_to @user
    else
      render 'new'
    end
  end

  def update
  end

  def destroy
  end

  def favorites
  end

  private

    def user_params
      params.require(:user).permit(:name, :email, :password, :password_confirmation) # Potential Land-mine
     end

   def signed_in_user
     unless signed_in?
       store_location
       redirect_to signin_url notice: "Please sign in."
     end
   end

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

Я думаю, что проблема может заключаться в том, что я использую идентификаторы. У меня есть два идентификатора для пользователей и фильмов (user_id, id, movie_id, id).

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

Любая помощь приветствуется.


person Community    schedule 23.06.2014    source источник
comment
У вас неправильно закодирована модель Favorite. Эта строка belongs_to :user_id, class_name: "User" неверна. Она должна быть просто belongs_to :user   -  person Pavan    schedule 23.06.2014
comment
Спасибо что подметил это. Я исправил это, но я все еще получаю ту же ошибку. Я сейчас обновлю свой OP   -  person    schedule 23.06.2014
comment
В какой строке вы получаете ошибку?   -  person Pavan    schedule 23.06.2014
comment
Строка 3 моего файла Favorites.html.erb. я обновлю свой пост   -  person    schedule 23.06.2014
comment
Теперь это имеет смысл. Пожалуйста, опубликуйте свой код контроллера. У вас есть @user ноль.   -  person Pavan    schedule 23.06.2014


Ответы (2)


Ваше значение @user равно нулю, потому что вы не определили его в своем контроллере для связанного метода.

Исправить

В контроллере добавьте эту строку @user = User.find(params[:id]) в метод favorites, как показано ниже.

def favorites

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

end
person Pavan    schedule 23.06.2014
comment
Я вижу, но один вопрос. Знак @ представляет собой переменную экземпляра, и я думал, что переменные экземпляра можно вызывать где угодно, даже вне метода. Нужно ли его вызывать для каждого метода? - person ; 23.06.2014
comment
@ user3760731 См. это stackoverflow.com/questions/14120078/ должен ответить на ваш вопрос. - person Pavan; 23.06.2014
comment
У меня есть только еще один вопрос. Когда я ввел этот код, я получил ошибку ActiveRecord::RecordNotFound in UsersController#favorites. Он сказал, что не может найти пользователя без идентификатора. Было ли это связано с тем, что я создал два дополнительных идентификатора, показанных в файлах миграции? - person ; 23.06.2014
comment
@ user3760731 Что произойдет, если вы измените эту строку на @user = User.find(params[:user_id])? - person Pavan; 23.06.2014
comment
@ Паван Похоже, та же проблема. Может быть, вместо этого использовать сильные параметры? Это тоже не сработало. Затем он сказал ParameterMissing для user_params - person ; 23.06.2014
comment
@user3760731 user3760731 В какой строке появляется эта новая ошибка? - person Pavan; 23.06.2014
comment
RecordNotFound — строка 34 ParameterMissing — строка 40, оба пользовательских контроллера - person ; 23.06.2014
comment
@user3760731 user3760731 Лучше опубликуйте еще один вопрос с решением этой проблемы. - person Pavan; 23.06.2014

Если вы собираетесь использовать has_many :through, вам нужно будет включить обе модели в отношения belongs_to в вашей модели соединения:

#app/models/favorite.rb
Class Favorite < ActiveRecord::Base
    belongs_to :user
    belongs_to :movie
end

введите здесь описание изображения

Вы также можете изменить ссылку на :favorite_movies на просто :movies:

#app/models/user.rb
Class User < ActiveRecord::Base
   has_many :favorites
   has_many :movies, through: :favorites
end

#app/models/movie.rb
Class Movie < ActiveRecord::Base
    has_many :favorites
    has_many :users, through: :favorites
end

Я не читал учебник, который вы использовали, поэтому не могу комментировать вашу текущую настройку; однако то, что я предложил, является самым элементарным способом "Rails" для этого.

Надеюсь, это поможет дальше!

person Richard Peck    schedule 23.06.2014
comment
Спасибо за Ваш ответ. - person ; 23.06.2014