我有两张表data_elements
和types
。用于存储静态类型列表的类型,包含两列:id
和name
。 data_elements
有type
列,应在id
表中引用types
。当通过HTML表单创建DataElement
时,类型列表显示为下拉列表,一切正常。我需要通过api调用创建DataElement
,并且我想验证作为REST调用的参数传递的type
实际上是存储在types
表中的类型之一。我无法弄清楚如何做到这一点。我很感激任何建议。
答案 0 :(得分:0)
如果您想在模型方面处理此问题,建议您创建“自定义属性”,这样您就不会影响现有type
字段的现有功能。这些方面的东西:
应用/模型/ data_element.rb 强>
def type_name=(value)
found_type = Type.find_by(name: value.to_s)
self.type = found_type unless found_type.nil?
end
def type_name
type.try(:name)
end
应用/控制器/ data_elements_controller.rb 强>
def create
@data_element = DataElement.new(data_element_params)
@data_element.save
end
def data_element_params
# Please ensure that `type` is not present in `permit`
params.require(:data_element).permit(:whatever, :type_name, :other_field)
end
通过这种方式,您可以处理type_name
,就像它是属性一样。您甚至不需要验证:如果找不到该名称的Type
,您只需更改该值(实际上您可以报告错误甚至验证)。
显然,如果您也使用type
,那么@data_element.update_attributes(type_name: 'foo', type: Type.first)
之类的内容会导致奇怪的结果(type
之后会发生Type.first
分配,因此您最终会{{1}而不是名为Type
的{{1}},所以如果您在分配中使用'foo'
,请确保在此时间内不使用type_name
,但不应该是问题,只是不要把它放在type
参数
我的第一个建议是“不要使用类型”作为表/型号名称。 Rails单表继承通常使用permit
列,这是主要原因。即使将其称为DataElementType也已经可以,但无论如何这都是您的选择。
关于你的问题,有多种方法可以做到这一点,我想到的第一个方法是
应用/模型/ type.rb 强>
type
应用/控制器/ data_elements_controller.rb 强>
class Type
validates :name, presence: true, uniqueness: { case_sensitive: false }
end
你可能想稍微重构一下这个方法,但这肯定会给你一个大概的想法。
答案 1 :(得分:0)
我同意@Fire-Dragon-DoL建议不要使用type
,因为它通常由STI使用。在您的情况下,如果您不在types
表中存储太多数据,我建议您定义一个类似ELEMENT_TYPES
的常量,这是一个包含您在DataElement
模型中使用的所有类型的数组。然后添加类似
class DataElement < ActiveRecord::Base
validates :type, inclusion: { in: ELEMENT_TYPES }`
end
如果是这样,您可以避免在保存data_element对象时编写冗余逻辑来验证type
属性。
您可以使用options_for_select(container, selected = nil)方法完成选择框。如果选项值和选项名称相同,那么您应该只使用container
替换DataElement::ELEMENT_TYPES
参数。如果没有,您最好定义一个辅助方法,如:
def types_container
DataElement::ELEMENT_TYPES.map do |type|
[DataElement.human_attribute_name(type), type]
end
end
然后只需用container
辅助方法替换types_container
参数。如果您要翻译类型的值,这应该是您的选择。如果这是您需要的,您可能必须在rails中知道名为I18n的内容。
希望我的回答可以提供帮助。
<强>更新强>
好吧,如果你坚持使用db存储你的数据,就不难满足需要。
我认为type
有很多data_elements
,您的架构看起来像:
ActiveRecord::Schema.define(version: 20150708021148) do
create_table "data_elements", force: :cascade do |t|
t.integer "de_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "types", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
(您可能需要在de_type
上添加索引或类似内容以提高查询效率)
首先,在DataElement和Type模型中定义关联关系:
应用/模型/ type.rb 强>
class Type < ActiveRecord::Base
has_many :data_elements
end
应用/模型/ data_element.rb 强>
class DataElement < ActiveRecord::Base
belongs_to :type, foreign_key: 'de_type'
end
这样,您就可以轻松通过type
获取data_element
个对象,或通过data_elements
获取type
。
然后您只需要向DataElement
模型添加验证:
validates :type, presence: true
如果de_type
表的id集合中不存在types
,则此验证将无法通知更新或创建。
我将在rails控制台中向您展示它的工作原理:
2.1.1 :006 > Type.all
=> #<ActiveRecord::Relation [
#<Type id: 1, name: "type1", created_at: "2015-07-08 02:17:33", updated_at: "2015-07-08 02:17:33">,
#<Type id: 2, name: "type2", created_at: "2015-07-08 02:17:38", updated_at: "2015-07-08 02:17:38">,
#<Type id: 3, name: "type3", created_at: "2015-07-08 02:17:39", updated_at: "2015-07-08 02:17:39">,
#<Type id: 4, name: "type4", created_at: "2015-07-08 02:17:41", updated_at: "2015-07-08 02:17:41">,
#<Type id: 5, name: "type5", created_at: "2015-07-08 02:17:43", updated_at: "2015-07-08 02:17:43">
]>
你可以发现我为types
创建了一些记录。现在我将尝试创建一些data_elements:
2.1.1 :009 > DataElement.create!(de_type: 7)
ActiveRecord::RecordInvalid: Validation failed: Type can't be blank
嗯,正如您所见,我尝试创建一个de_type
7 的data_element。你找不到id为7的type
记录,对吗?所以你终于看到引发了RecordInvalid错误,错误信息是Type can't be blank
。
现在,让我们创建一个没有任何错误的data_element:
2.1.1 :010 > DataElement.create!(de_type: 2)
(0.1ms) begin transaction
Type Load (131.0ms) SELECT "types".* FROM "types" WHERE "types"."id" = ? LIMIT 1 [["id", 2]]
SQL (1.1ms) INSERT INTO "data_elements" ("de_type", "created_at", "updated_at") VALUES (?, ?, ?) [["de_type", 2], ["created_at", "2015-07-08 03:05:51.046949"], ["updated_at", "2015-07-08 03:05:51.046949"]]
(6.3ms) commit transaction
=> #<DataElement id: 4, de_type: 2, created_at: "2015-07-08 03:05:51", updated_at: "2015-07-08 03:05:51">
那么,记录是否成功创建,有意思? 您可以在rails guide中找到更多信息(抱歉,我无法发布超过2个链接)