帖子模型和控制器架构
我正在尝试开发一个简单的网站,让用户可以添加帖子并在一个聚合流中查看所有帖子。
问题是我有两种“类型”的帖子,“消息”帖子和“链接”帖子。
所有帖子必须有消息并且帖子可以有链接。
如果帖子有链接,则该链接必须是唯一的,因此您无法添加带有已提交(由您或其他用户提交)的链接的帖子。
因此,如果用户添加带有提供的链接 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,所以我像这样应用 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 和验证的良好资源,请给我一个链接。
I am trying to develop a simple site that lets users add posts and view them all in one aggregated stream.
The problem is that I have posts of 2 "types", the "message" post and the "link" post.
All post must have a message and post can have a link.
If post has a link it must be unique so you cant add a post with link that already was submitted (by you or some other user).
So, in case if user adds the Post with provided link URL I need validations for link like:
- is this a link?
- is this link new (not already in db)?
- is this a valid link (like the domain exists and the server response is adequate (400,301,...)
Now I am stuck with just one model for all the posts (with links and without them) that looks like this:
#
# 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
The problem as I see it is that I cant apply model validation to link (cant check uniqueness or format) because it can be NULL, so I apply all the validations in posts_controller like this:
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
How to make this the right way? I got a suggestion to use STI for this, but I don't really know how to do it the right way and how to apply validation. If you know of good resource about using STI and validations please give me a link.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在 Rails 中,每当你发现自己做了一些不寻常的事情时,它可能是错误的。或者,如果没有错的话,这可能意味着需要付出大量努力才能实现您想要实现的目标。验证通常在模型上完成,控制器中不应该有与简单路由无关的代码。因此解决这个问题的正确方法是将验证代码放入模型中。在 Rails 3 中,我会有一个类似这样的验证器 - 我没有详细介绍控制器代码,但希望您能明白...
然后在 Post 模型中调用验证器
: STI - 看看这篇文章
In rails, whenever you find yourself doing something that is unusual, it is probably wrong. Or if not wrong, it will probably mean a lot of work trying to achieve what you want to achieve. Validation is usually done on the model, and there should never be code in the controller that is not to do with simple routing. So the right way to address this is to put the validation code in the model. In rails 3, I would have a validator something like this - I've not put in the detail of your controller code, but hopefully you get the idea ...
Then in the Post model you call the validator:
As to using validation in STI - take a look at this post