假设我有两种模式:客户端和产品
客户的“用户名”和“电子邮件”应为“唯一索引”,作为产品的“序列号”
当用户在作为唯一索引的表单字段上键入时,我有一个onblur函数,它使用属性名称和属性值向控制器发送请求。如果存在值,则立即通知用户。
在ClientController中,我编写了一个函数来检查它是否唯一,并返回-2表示错误,-1表示不存在,或者正数(id)(如果存在)。
def unique
if params[:attrName].blank? or params[:attrValue].blank?
id = "-2"
else
cli = Client.where("#{params[:attrName]} = '#{params[:attrValue]}'").first
if cli != nil
id = cli["id"]
else
id = "-1"
end
end
render :json => {
:id => id
}
end
由于许多原因(SQL注入漏洞,违反DRY,因为每个控制器具有基本相同的方法),这并不好。
我正在考虑在ApplicationController中编写“unique”函数,但正如您在上面看到的,如果它是客户端,我应该可以调用“Client.where”,如果是产品,我应该能够调用“Product.where”。我怎样才能最“一般”地建立这个功能,最安全?我正在考虑原始SQL,但我认为这是一种天真的方法。
答案 0 :(得分:3)
为此避免使用原始SQL是明智的。
这会有用吗?
class ApplicationController < ActionController::Base
def unique
id = if params[:attrName].blank? || params[:attrValue].blank?
-2
elsif found = model_name.where(params[:attrName] => params[:attrValue]).take
found.id
else
-1
end
render json: { id: id }
end
end
您可以将其放在application_controller.rb
中,然后在ClientsController
和ProductsController
中定义model_name
方法:
class ClientsController < ApplicationController
def model_name
Client
end
end
class ProductsController < ApplicationController
def model_name
Product
end
end
这可行,但可能不太理想。如果模型存在与否,您可能希望让Rails使用find
进行更多工作,并使用strong params来验证您需要的参数是否存在。
答案 1 :(得分:1)
您可以将其移动到模块并使其返回ActiveRecord
关系。如果你愿意,你可以将其与其他ActiveRecord relations
链接起来,以及(注意我在我的sql条件中使用?
而不是指示给出参数)
#module
module UniqueRecord
module ClassMethods
def unique(params)
where(params)
end
end
def self.included(receiver)
receiver.extend ClassMethods
end
end
并在你的班级中使用它
#client.rb
class Client < ActiveRecord::Base
include UniqueRecord
end
#product.rb
class Product < ActiveRecord::Base
include UniqueRecord
end
所以现在你的两个类都有unique
方法可用。
你可以从你获得的键和值创建一个哈希,例如:你可以动态创建一个哈希来搜索电子邮件,如
hash = {email: 'same@email.com'}
然后调用方法
Client.unique(hash)
如果您愿意,可以通过类名字符串
调用它'Client'.constantize.unique(hash)
还有一件事,最好返回一个对象数组(如果找到)或空白数组(如果没有找到)而不是-1,-2。这将使你的api保持一致。像
Client.unique(hash).to_json