我正在尝试开发一个简单的网站,让用户可以在一个聚合流中添加帖子并查看所有帖子。
问题是我有2个“类型”的帖子,“消息”帖子和“链接”帖子。
所有帖子都必须有消息,帖子可以有链接。
如果帖子有链接,则它必须是唯一的,因此您无法添加包含已经提交的链接的帖子(由您或其他某些用户)。
因此,如果用户使用提供的链接URL添加帖子,我需要对链接进行验证,如:
现在我只对所有帖子(带链接,没有链接)的模型感到困惑,如下所示:
#
# 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,因此我在posts_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和验证的良好资源,请给我一个链接。
答案 0 :(得分: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中使用验证 - 请查看this post