0

我正在尝试开发一个简单的网站,让用户可以添加帖子并在一个聚合流中查看它们。

问题是我有两种“类型”的帖子,“消息”帖子和“链接”帖子。

所有帖子都必须有消息,并且帖子可以有链接。

如果帖子有链接,它必须是唯一的,因此您不能添加带有已经提交的链接的帖子(由您或其他用户)。

因此,如果用户使用提供的链接 URL 添加帖子,我需要对链接进行验证,例如:

  • 这是一个链接吗?
  • 这个链接是新的(不在数据库中)?
  • 这是一个有效的链接(就像域存在并且服务器响应足够(400,301,...)

现在,对于所有看起来像这样的帖子(有链接和没有链接),我只使用一个模型:

#
# Table name: posts
#
#  id           :integer(4)      not null, primary key
#  message      :string(255)     default(""), not null
#  link         :string(2000)
#  src_site_id  :integer(4)
#  link_type    :integer(4)      default(0)
#  explicit     :boolean(1)      default(FALSE)
#  view_times   :integer(4)
#  hidden_times :integer(4)
#  tasted_times :integer(4)
#  uid          :integer(4)
#  created_at   :datetime
#  updated_at   :datetime
#

class Post < ActiveRecord::Base
  default_scope :order => 'created_at desc'

  attr_accessible :link, :message, :explicit

  validates :message, :presence => true,
                      :length   => { :maximum => 255 }

end

我看到的问题是我无法将模型验证应用于链接(无法检查唯一性或格式),因为它可以为 NULL,所以我在 post_controller 中应用所有验证,如下所示:

class PostsController < ApplicationController

  def create
    @post = Post.new(params[:post])

    if @post.link.empty?
       @post.link = nil
       @post.save
    else 
      if looks_like_link(@post.link) 
        if is_new_link(@post.link) 
          if is_valid_link (@post.link)
            @post.save
          else # url is not available
            flash['error'] = 'link is not available'
          end
        else # link is already in db
            flash['error'] = 'link is already added'
        end
      else 
        flash['error'] = 'doesnt look like a link'
      end

    end

    redirect_to(root_path)
  end

  private

  def looks_like_link(link)
    link.match(/^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix)? true : false
  end 

  def is_new_link(link)
    Post.find_by_link(link) ? false : true
  end

  def is_valid_link(link)
    require "net/http"
    url = URI.parse(link)
    req = Net::HTTP.new(url.host, url.port)
    res = req.request_head(url.path)

    flash[:error] = 'res code is ' + res.code 
    return res.code == '200' || res.code == '301' ? true : false

  end
end

如何以正确的方式做到这一点?我收到了使用 STI 的建议,但我真的不知道如何以正确的方式进行操作以及如何应用验证。如果您知道有关使用 STI 和验证的良好资源,请给我一个链接。

4

1 回答 1

0

在 Rails 中,每当您发现自己在做一些不寻常的事情时,这可能是错误的。或者,如果没有错,这可能意味着要努力实现您想要实现的目标。验证通常在模型上完成,控制器中不应该有与简单路由无关的代码。所以解决这个问题的正确方法是将验证代码放入模型中。在 Rails 3 中,我会有一个类似这样的验证器——我没有详细介绍你的控制器代码,但希望你能明白......

 class LinkValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if record.empty? 
return true 
   else
      Post.find_by_link(record) ? false : true
    end
  end
end

然后在 Post 模型中调用验证器:

validates :link, :link=>true, :allow_nil => true

至于在 STI 中使用验证 - 看看这篇文章

于 2011-08-23T07:14:33.533 回答