【问题标题】:Ruby on Rails: assign relationship on creationRuby on Rails:在创建时分配关系
【发布时间】:2015-04-23 21:21:56
【问题描述】:

我是 Ruby on Rails 的新手。我的项目中有两个模型:房间和客人。关联是“房间有_很多客人”和“客人属于房间”。

我为管理房间和客人设置了不同的视图。房间不需要“客人”的创造价值。但是,我想创建新客人并同时将其分配到某个房间。正确的方法是什么?如何从网络传输输入并匹配数据库中的实体。

代码与"Getting Started with Rails" 几乎相同。在教程中,他们在“文章”视图中添加了“cmets”,并使用“评论”作为“文章”的子资源。就我而言,我平等对待这两个模型,并希望在单独的视图中管理它们。

更新:

我使用了 collection_select 并尝试使用我的 guest_controller。

<%= form_for :guest, url: guests_path do |f| %>
<% if @guest.errors.any? %>
  <div id="error_explanation">
    <h2>
      <%= pluralize(@guest.errors.count, "error") %> prohibited this guest from being added:
    </h2>
    <ul>
      <% @guest.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
      <% end %>
    </ul>
  </div>
<% end %>

  <p>
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :phone %><br>
    <%= f.text_field :phone %>
  </p>
  <p>
    <%= f.label :room%><br>
    <%= f.text_field :room %>
  </p>
  <p>
  <%= f.label :room %><br>
  <%= f.collection_select(:room_id, Room.all, :id, :title) %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>

<%= link_to 'Back', guests_path %>

在我的guest_controller中,上面表格调用的create方法是:

    def create
        @guest = Guest.new(guest_params)
        @guest.room = Room.find(params[:room_id])
        if @guest.save
            redirect_to @guest
        else
            render 'new'
        end
    end

但是,当我创建一个新来宾时,它显示:

ActiveRecord::RecordNotFound in GuestsController#create
Couldn't find Room with 'id'=

我检查了 room_id=4 和 Room.find(4) 返回了正确的房间。 怎么了?

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    如果您想从现有的房间中选择一个房间,请使用collection_select form helper,这是文档中的相关 sn-p:

    f.collection_select(:city_id, City.all, :id, :name)
    

    这会输出一个下拉列表:

    • 在此上下文中填写city_id参数
    • 使用City.all 填写列表中的选项(我将“每个”城市称为city
    • 使用city.id 作为数据(以表格形式发送)
    • 在下拉列表中为每个城市显示city.name(希望是人类可读的)

    但请记住,就安全性而言,它就像 “看,你可以选择这个,这个和这个!”,这并不妨碍用户选择未列出的选项:要么通过手动修改表单标记或发送手工查询。

    因此,如果您曾经限制对特定房间的访问,并且只列出 Room.unlockedunlocked 假定一个范围),请确保收到的 room_id 也指该范围内的一个房间。大多数问题都可以通过验证或仔细的关联管理来处理(Room.unlocked.find_by_id(:room_id),如果房间不在该范围内,则输出nil)。

    UPD: 至于您最近遇到的问题——您对params 中表单内容的理解似乎是错误的。实际上这是一个很常见的误解。

    form_for :guest 将在params[:guest] 中构造一个单独的对象/哈希,其中包含所有表单的字段。所以它实际上在params[:guest][:room_id] 里面,但是不,不要急于添加缺少的部分

    您已经从整个params[:guest] 构建了一个@guest 对象,因此如果房间确实存在,那么它已经在@guest.room 内部,并且可以在save 期间在模型内部进行验证。看看Rails validators

    【讨论】:

    • 感谢您的回答!我使用了 collection_select 并遇到了新问题。请检查我对这个问题的更新。谢谢!
    • @HaoboChen 为什么在创建操作中需要@guest.room = Room.find(params[:room_id])?无需查找房间,因为您的 collection_select 只能包含存在的房间,因此无需检查。只要您在 Guest 表中有一个 room_id 列并设置它,关系就应该没问题。
    • @thirdsun 一个表单被浏览器提交,可以被篡改。
    • @HaoboChen 如果您不限制允许的房间范围,验证room 的存在应该足够了。验证将在save 上触发,并将阻止对不存在的房间的引用。如果有适当的访问控制,事情只会变得复杂。
    • @D-side 确实是这样,没想到,错过了你答案的最后一部分。
    【解决方案2】:

    看看fields_for标签:

    http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for

    它只允许在创建房间并相互关联的同时创建客人。

    【讨论】:

    • 实际上,我想创建一个客人并将其分配给现有房间。另一个问题是我需要什么样的输入值来识别房间。
    • 如果您需要分配给现有房间,这很容易,@D-Side 解决方案就是其中之一,belongs_to 关联意味着 Guest 模型中有一个 room_id 列,因此使用 collection_select或 check_box 表单项足以将客人与房间相关联。
    • 感谢您的回复!我对我的问题做了一些更新。请检查一下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多