如何从ApplicationController

时间:2015-08-26 01:49:11

标签: ruby-on-rails ruby ruby-on-rails-4

假设我有两种模式:客户端和产品

客户的“用户名”和“电子邮件”应为“唯一索引”,作为产品的“序列号”

当用户在作为唯一索引的表单字段上键入时,我有一个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,但我认为这是一种天真的方法。

2 个答案:

答案 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中,然后在ClientsControllerProductsController中定义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