【问题标题】:How to select appropriate Association in Rails?如何在 Rails 中选择合适的关联?
【发布时间】:2012-10-24 21:41:15
【问题描述】:

我正在尝试通过创建一个非常简单的应用程序来学习 Rails,该应用程序只是创建一个网站,人们可以在该网站上创建作者和书籍的列表,并与该书由作者撰写的关联。我希望这会简单而干燥,但我遇到了意想不到的麻烦。

首先查看我的模型,我已经建立了关联并制作了所需的每个数据点(author.name、book.title 和 book.author)。我不想将 :author 或 :author_id 添加到 attr_accessible 列表中,因为我想使用适当的 Rails 约定。

app/models/author.rb:

class Author < ActiveRecord::Base
  attr_accessible :name
  validates_presence_of :name
  has_many :books
end

app/models/book.rb:

class Book < ActiveRecord::Base
  attr_accessible :title
  validates_presence_of :title
  belongs_to :author
  validates_associated :author
end

我认为书籍控制器和视图完全来自脚手架,非常无趣。有趣的是书籍控制器。查看新方法,我所做的只是添加一个收集器,它获取带有 id 的作者姓名数组以传递给视图。 (老实说,我想我宁愿根本不传递 id。)

app/controllers/books_controller.rb

  # GET /books/new
  # GET /books/new.json
  def new
    @book = Book.new
    @authors = Author.all.collect {|a| [a.name, a.id]}

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @book }
    end
  end

现在转到视图,我使用默认的 new.html.haml,但对 _form.html.haml 进行了更改。我使用@authors 中的值添加了一个选择字段。

app/views/books/_form.html.haml

= form_for @book do |f|
  - if @book.errors.any?
    #error_explanation
      %h2= "#{pluralize(@book.errors.count, "error")} prohibited this book from being saved:"
      %ul
        - @book.errors.full_messages.each do |msg|
          %li= msg

  .field
    = f.label :name
    = f.text_field :name
  .field
    = f.label :author
    = f.select(:author, @authors, {:include_blank => ""})
 .actions
    = f.submit 'Save'

最后,回到我的控制器的 create 方法。我尝试保存基本参数并根据所选作者创建作者关联。

app/controllers/books_controller.rb

  # POST /books
  # POST /books.json
  def create
    @book = Book.new(params[:book])
    @book.author = Author.find_by_id(params[:author])

    respond_to do |format|
      if @book.save
        format.html { redirect_to @book, notice: 'Book was successfully created.' }
        format.json { render json: @book, status: :created, location: @book }
      else
        format.html { render action: "new" }
        format.json { render json: @book.errors, status: :unprocessable_entity }
      end
    end
  end

当我点击“保存”时,我收到以下错误:

Can't mass-assign protected attributes: author

我知道这是因为我选择的值放在了 params[:book] 而不是 params[:author] 中。所以我有两个问题。

1) 如何修复我的 select 语句,让它在 params[:author] 而不是 params[:book] 中发送?

2) 有没有更好的方法来完全隐藏 id 关联?

【问题讨论】:

    标签: ruby ruby-on-rails-3 activerecord associations


    【解决方案1】:

    “无法批量分配受保护的属性:作者”表示您的属性未在您的模型中列为 attr_accessible

    【讨论】:

    • 是的,这是故意的。不过,我的问题的关键是如何在不改变模型的情况下使这个“工作”?
    【解决方案2】:

    我想我基本上已经弄明白了,而且正如我所怀疑的那样,我根本不需要更改我的模型代码。

    我将控制器的 @authors 新方法定义更改为仅返回具有以下内容的作者姓名:

    @authors = Author.pluck(:name)
    

    这实现了我隐藏 id 的目标,尽管当我需要在控制器创建方法(如下)中按名称而不是 id 进行搜索时,它可能会慢一点。

    接下来,我将视图固定为设置 params[:author] 而不是 params[:book][:author]。

    = label :author, :name, 'Author'
    = select_tag(:author, options_for_select(@authors), {:include_blank => ""})
    

    最后,我更改了@book 的新方法创建:

    @book = Author.find_by_name(params[:author]).books.create(params[:book])
    

    我对此很满意。我唯一不喜欢的是标签创建了一个“author_name”标签,而不是简单的“author”。

    【讨论】:

    • 糟糕,我想我可以使用 label_tag :author。
    • 我最终将控制器更改为 @book = Book.new(params[:book])@book.author = Author.find_by_name(params[:author])。这更容易阅读,不会导致大量属性警告,并确保我有一个 @book,如果我因为错误需要重新渲染,它可以标记错误。
    猜你喜欢
    • 2018-09-28
    • 1970-01-01
    • 2018-02-15
    • 1970-01-01
    • 2016-06-16
    • 1970-01-01
    • 2012-06-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多