帖子模型和控制器架构

发布于 2024-12-01 04:37:35 字数 2426 浏览 3 评论 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,所以我像这样应用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风流物 2024-12-08 04:37:35

在 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 - 看看这篇文章

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 ...

 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

Then in the Post model you call the validator:

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

As to using validation in STI - take a look at this post

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文