在Ruby on Rails中,是否可以在多次验证中调用方法?

时间:2014-10-02 08:50:11

标签: ruby-on-rails ruby regex validation

我试图找出它可以在验证期间执行方法调用,该方法调用会改变进入数据库的某些属性的信息。所需的工作流程是:用户提交网址,我验证它,如果它与正则表达式匹配,则调用嵌入。 embedly函数获取title和image_url的信息。我也希望对title和image_url进行验证,但这些都不存在,直到我称之为embedly方法。

有没有办法: 1.验证link_url 2.调用嵌入式方法 3.验证生成的title和image_url属性?

感谢任何帮助:

    class ListLink < ActiveRecord::Base
    belongs_to :list
    default_scope -> {order('created_at DESC')}

    #the REGEX urls are matched against
    VALID_URL_REGEX = /\A(http:\/\/|https:\/\/|www|)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?\z/i

    validates :link_url, presence: true,
    format:{with: VALID_URL_REGEX, message: "Please enter a valid url."}
    validates :list_id, presence: true

    #if is a valid url, ping embedly for more information on it
    before_save :embedly

    #is it possible to call just these 2 validations after the :embedly method?
    validates :title, presence: true, length:{minimum: 4, maximum: 200}
    validates :image_url, presence: true


  private
    def embedly
        embedly_api = Embedly::API.new :key => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
                :user_agent => 'Mozilla/5.0 (compatible; mytestapp/1.0; my@email.com)'
        #duplicate the url for use in the embedly API
        url = link_url.dup
        obj = embedly_api.extract :url => url
        #extract and save a title and image element to the database
        self.title = obj[0].title
        self.image_url = obj[0]["images"][0]["url"]
    end
end

4 个答案:

答案 0 :(得分:0)

你可以写一个before_validation回调来检查你的link_url以及它是否有效(即如果它与网址匹配),执行你的嵌入式内容。然后,在常规验证期间,您仍然可以将错误消息添加到无效的link_url。这看起来像这样:

class ListLink < ActiveRecord::Base
  before_validation :embedly_if_valid

  # the REGEX urls are matched against
  VALID_URL_REGEX = /\A(http:\/\/|https:\/\/|www|)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?\z/i

  validates :link_url, presence: true,
    format:{with: VALID_URL_REGEX, message: "Please enter a valid url."}

  validates :list_id, presence: true
  validates :title, presence: true, length:{minimum: 4, maximum: 200}
  validates :image_url, presence: true

  private
  def embedly_if_valid
    embedly if self.link_url =~ VALID_URL_REGEX
  end

  def embedly
    embedly_api = Embedly::API.new :key => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
            :user_agent => 'Mozilla/5.0 (compatible; mytestapp/1.0; my@email.com)'
    #duplicate the url for use in the embedly API
    url = link_url.dup
    obj = embedly_api.extract :url => url
    #extract and save a title and image element to the database
    self.title = obj[0].title
    self.image_url = obj[0]["images"][0]["url"]
  end    
end

请注意,如果title无效,您可能会收到image_urllink_url字段的验证错误。如果不希望将link_url设置为nil before_validation,除非它有效,否则您可能会对此进行编码。

答案 1 :(得分:0)

我建议不要使用before_save回调,而是在link_url的自定义设置器中执行此操作,这类似于......

def link_url=(url)
  if url =~ VALID_URL_REGEX
    super
    embedly
  end
end

或者,如果您没有致电link_url = ...,请在before_validation回调中执行此操作。

答案 2 :(得分:0)

你不能像你在这里提到的那样去做。根据对象的状态,您似乎有不同的验证。

相反,您可以在保存之前运行embedly,然后验证所有内容。如果您需要进行某些验证才能使用embedly方法,则可以使用form object (example #3)分隔流程的不同步骤。

您还可以使用before_validation来运行embedly,但是您需要在embedly所需的字段上复制验证(您需要在方法中对其进行测试)在验证之前,然后在模型上,以防您以后需要重新运行该方法)。你可以通过一个名为explicitely的自定义验证方法来传递它,但我并不是它的忠实粉丝。

答案 3 :(得分:0)

我会重新考虑一下设计。调用像Embedly这样的外部服务最好是作为后台工作完成,因为你永远不知道要花多长时间,它可以阻止你的应用程序的其他请求。

但是,您必须允许创建ListLink而不使用title和image_url。然后,您的后台工作程序将在运行时设置这些属性。

当然,您仍然希望在此时验证它们,但这可以使用条件验证来完成。像这样:

validates :title, presence: true, length:{minimum: 4, maximum: 200}, unless: :new_record?