在表单中输入名称,但将id保存为外键

时间:2016-05-15 16:14:52

标签: ruby-on-rails

我正在尝试创建一个表单,其中可以输入:外部模型实例的名称,该实例应该转换为该对象的id,以作为外键存储。

我找到了不同的方法,但它们都有很大的缺点。 例如:我有两个模型A和B:

class A < ActiveRecord::Base
  belongs_to :b
  validates :b_id, presence: true, inclusion: {in: B.all.map(&:id)}
end

class B < ActiveRecord::Base

end

_form.html.erb使用此字段,可以输入字符串:

<%= form_for(@a) do |f| %>
  ...
  <div class="field">
    <%= f.label :b %><br>
    <%= f.text_field :b %>
  </div>
  ...
<% end %>

虽然A的控制器看起来像这样:

class AController < ApplicationController
  ...
  before_action :get_a_id, only: [:create, :update]
  ...

  private

    def page_params
      params.require(:a).permit(:name, :b_id, :content)
    end

    def get_a_id
      b_name = params[:a][:b]
      b = B.find_by(name: b_name)
      b_id = b.id unless b.nil?
      params[:a][:b_id] = b_id
    end

end

如果在数据库中找到了在文本字段中输入的:name,则此方法可以正常工作。如果未找到,则显示验证错误,但text_field未突出显示,然后为空(而不是包含先前输入的字符串)。 我认为这是因为该字段应包含B的Object而不是名称,如果字符串错误则不存在。 我认为,完全不应该像这样操纵它。

有没有很好的方法来实现这一目标?我不想在这里下载,因为之后可能会有很多值。当然下一步将是实现某种自动完成,但这不应该算在这里。

理论上应该有一种方法可以将text_field与一个新的B对象相关联,但只显示:name。然后,控制器可以尝试查找具有该名称的数据库对象,并用它替换占位符。如果找不到合适的对象,则验证失败,但仍然显示该值(当然需要更改验证)。

任何方式以一种很好的方式实现这样的事情是值得赞赏的。如果有什么不清楚,请告诉我。

修改
我真正想要实现的目标:

允许输入字符串的表单字段。该字符串应该传递给执行搜索的控制器,该控制器将该字符串转换为对象的ID(B),以便它可以用作外键。保存类A的Object时,验证程序应检查ID是否已设置且是否存在。如果验证失败,则应突出显示字段(带字符串)并显示错误消息。

主要问题是,具有名称的字符串不在模型中。只是id是。因此,如果验证了id(什么是正确的方法),则错误消息将不会与包含名称为字符串的字段相关联。

1 个答案:

答案 0 :(得分:1)

更新:了解全貌后:

您需要虚拟属性。然后您可以执行@a.set_b_name=,它将执行查找并应用名称,或者您可以将名称存储在实例var中并对其使用验证。  有关更多详细信息,请参阅以下链接:)

旧答案是:

如果找不到B,即b.nil ?,那么你会创建一个新的&#39; b&#39;数据库中没有的对象; b = B.new(name: params[:name])