我正在尝试创建一个表单,其中可以输入:外部模型实例的名称,该实例应该转换为该对象的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(什么是正确的方法),则错误消息将不会与包含名称为字符串的字段相关联。
答案 0 :(得分:1)
更新:了解全貌后:
您需要虚拟属性。然后您可以执行@a.set_b_name=
,它将执行查找并应用名称,或者您可以将名称存储在实例var中并对其使用验证。
有关更多详细信息,请参阅以下链接:)
旧答案是:
如果找不到B,即b.nil ?,那么你会创建一个新的&#39; b&#39;数据库中没有的对象; b = B.new(name: params[:name])
。