【问题标题】:How to call the model's where(...) method from ApplicationController如何从 ApplicationController 调用模型的 where(...) 方法
【发布时间】:2015-08-26 01:49:11
【问题描述】:

假设我有两个模型:客户端和产品

Client的“username”和“email”应该是“唯一索引”,作为Product的“serialnumber”

当用户在唯一索引的表单字段上键入时,我有一个 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 中编写“唯一”函数,但正如您在上面看到的,如果它是客户端,我应该能够调用“Client.where”,或者如果它是产品,我应该能够调用“Product.where”。如何以最“通用”的方式和最安全的方式构建此功能?我正在考虑原始 SQL,但我认为这是一种幼稚的方法。

【问题讨论】:

  • 这是你的目标吗?创建产品时,“用户名”和“电子邮件”组合成“序列号”类型的唯一索引,保存在产品表中。您的愿望是确保如果同一用户尝试创建另一个产品,任何产品,他们将被阻止,因为该用户名和电子邮件之前已用于创建产品。而且您没有使用模型活动记录关系来完成任何此类逻辑。是这样吗?
  • 没有。 “用户名”和“电子邮件”与“产品”无关。它们是“唯一索引”属性的示例。这就像当您创建一个电子邮件帐户时,当您键入所需的电子邮件时,您会立即收到关于它是否可用的反馈。这是因为当您键入时,电子邮件字符串会发送到服务器,并检查它是否已存在于数据库中。请阅读@yez 答案,因为它显示了我想要完成的工作
  • 好的。谢谢。我只是想知道。

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


【解决方案1】:

为此避免使用原始 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 来验证您需要的参数是否存在。

【讨论】:

  • 您可以通过从控制器名称中收集模型名称来进一步完善这一点 - 请参阅stackoverflow.com/questions/4869917/…(即controller_name.classify.constantize
  • 不错!我不知道一个方法可以简单地返回一个模型,就像你在“def model_name ...”中所做的那样
【解决方案2】:

您可以将其移至模块并使其返回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

【讨论】:

  • 我没有完全理解。那么,使用这种方法,我如何检查例如 Client 的属性“email”是否具有类似于“example@example.com”的值?会是这样吗? “def unique(attrName, attrValue) ... end” 并像“'Client.constantize.unique('email', 'example@example.com'”一样使用它?
  • 不错!我也试试这个
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-27
  • 2014-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-17
  • 1970-01-01
相关资源
最近更新 更多