协会没有创建

时间:2013-02-16 16:40:50

标签: ruby-on-rails

这个错误让我困扰了好几个星期。当我尝试从指定的ItemUser构建List时,会创建Item,但关联Wish不会。

如果我尝试@item.lists.first.name,则会返回错误:

undefined method 'name' for nil:NilClass

我对rails很新,所以我确信有些东西我错过了或被误解了。因此,非常感谢任何帮助!

我有四种模式:

class User < ActiveRecord::Base
  has_many :lists, dependent: :destroy
  has_many :wishes, through: :lists
  has_many :items, through: :wishes

class List < ActiveRecord::Base
  belongs_to :user
  has_many :wishes, dependent: :destroy
  has_many :items, through: :wishes

class Wish < ActiveRecord::Base
  belongs_to :list
  belongs_to :item

class Item < ActiveRecord::Base
  has_many :wishes
  has_many :lists, through: :wishes

我想从Item show动作中创建一个新的lists_controller.rb

class ListsController < ApplicationController
  def show
    @user = User.find(params[:user_id])
    @list = @user.lists.find(params[:id])
    @item = @list.items.build if current_user?(@user)
    @items = @list.items
  end

class ItemsController < ApplicationController
    def create
        @list = current_user.lists.find(params[:list_id])
        @item = @list.items.build(params[:item])
    if @item.save
      flash[:success] = "Item created!"
      redirect_to @item
    else
      render 'new'
    end
end

我的路线文件如下:

Wishlist::Application.routes.draw do
  resources :users do
    resources :lists, only: [:show, :create, :destroy]
  end
  resources :items, only: [:show, :new, :create, :destroy]

表单lists/show.html.erb

   <div class="modal-body">
     <%= form_for(@item, html: { multipart: true }) do |f| %>
  <div class="field">
        <%= render 'items/fields', f: f %>
         <%= hidden_field_tag :list_id, @list.id %>
  </div>
   </div>

items/fields

<%= render 'shared/error_messages', object: f.object %>

<%= f.label :image %>
<%= f.file_field :image %>

<%= f.label :remote_image_url, "or image URL" %>
<%= f.text_field :remote_image_url %>

<%= f.label :title %>
<%= f.text_field :title %>

<%= f.label :link %>
<%= f.text_field :link %>

更新

来自日志:

Processing by ItemsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"pcDVdaDzZz4M17Kwjx8mKw6tTF9MjUvx1woTzaKRWJY=", "item"=>{"image"=>#<ActionDispatch::Http::UploadedFile:0x007fecdd1fd890 @original_filename="profile.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"item[image]\"; filename=\"profile.jpg\"\r\nContent-Type: image/jpeg\r\n", @tempfile=#<File:/var/folders/6y/j8zfcgmd02x5s439c0np8fjh0000gn/T/RackMultipart20130216-8413-3vzjuj>>, "remote_image_url"=>"", "title"=>"YES", "link"=>"SDFs"}, "list_id"=>"1", "commit"=>"Add"}
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."remember_token" = '5AXS8-7-YRyLyGDKYHIZRg' LIMIT 1
  List Load (0.2ms)  SELECT "lists".* FROM "lists" WHERE "lists"."user_id" = 1 AND "lists"."id" = ? LIMIT 1  [["id", "1"]]
   (0.1ms)  begin transaction
  SQL (0.7ms)  INSERT INTO "items" ("created_at", "image", "link", "title", "updated_at") VALUES (?, ?, ?, ?, ?)  [["created_at", Sat, 16 Feb 2013 20:57:10 UTC +00:00], ["image", "profile.jpg"], ["link", "SDFs"], ["title", "YES"], ["updated_at", Sat, 16 Feb 2013 20:57:10 UTC +00:00]]
   (2.7ms)  commit transaction
Redirected to http://localhost:3000/items/1
Completed 302 Found in 830ms (ActiveRecord: 4.0ms)

3 个答案:

答案 0 :(得分:0)

让我首先尝试总结一下:你有用户,其中包含与一个特定项目相关的愿望的列表。

首先让我们先看看以下代码行:

@item.lists.first.name

所以会发生的是,rails获取该项目,遍历所有包含此项目的列表的愿望,获取第一个列表并查找列表名称。当项目与愿望中的任何列表无关时,您会看到问题(例如,因为您的项目创建方法没有将新项目连接到愿望,因此也缺少与列表的连接):所以项目没有关系到列表,@item.lists的结果是一个空列表。好吧,空列表的first元素没有任何内容(nil),当然nil没有名称。

结果是,你看到了什么:

undefined method 'name' for nil:NilClass

解决此问题的一种方法是使用try(),只有在相关方法可用时才执行相关方法:

@item.lists.first.try(:name)

您正在谈论的另一个问题是,当您从用户构建项目时,不会产生任何愿望。我认为你必须明确地建立愿望。我不是百分百肯定,但我认为,声明:through - 模型中的关系仅用于查询,而不用于生成/构建。

在你的项目控制器中尝试类似下面的内容(想法是首先明确地构建愿望,然后在构建愿望的项目之后):

@wish = @list.wishes.build()
@wish.save
@item = @wish.item.build(params[:item])

答案 1 :(得分:0)

build上使用has_many :through时,这似乎是一个已知问题(但不是真正的问题)。您需要更改itemsList的关联,以包含inverse_of

class List < ActiveRecord::Base
  belongs_to :user
  has_many :wishes, dependent: :destroy
  has_many :items, through: :wishes, inverse_of: :wishes
end

然后应该为您正确构建连接Wish对象。

有关详细信息,请参阅此相关问题:https://github.com/rails/rails/pull/7661#issuecomment-8614206

答案 2 :(得分:0)

经过大量的谷歌搜索和反复试验,我发现我必须明确地建立愿望。创建操作最终看起来像这样:

def create
    @list = current_user.lists.find(params[:list_id])
    @item = Item.create!(params[:item])
    @item.wishes.build(list_id: @list.id)
    if @item.save
      flash[:success] = "Item created!"
      redirect_to @item
    else
      render 'new'
    end
end