0

ユーザーが投稿を追加し、それらすべてを 1 つの集約されたストリームで表示できるシンプルなサイトを開発しようとしています。

問題は、「メッセージ」投稿と「リンク」投稿の 2 つの「タイプ」の投稿があることです。

すべての投稿にはメッセージが必要であり、投稿にはリンクを含めることができます。

投稿にリンクが含まれている場合は一意である必要があるため、(あなたまたは他のユーザーによって) 既に送信されたリンク付きの投稿を追加することはできません。

したがって、ユーザーが提供されたリンク URL を使用して投稿を追加する場合、次のようなリンクの検証が必要です。

  • これはリンクですか?
  • このリンクは新しいものですか (まだデータベースにありません)?
  • これは有効なリンクですか (ドメインが存在し、サーバーの応答が適切であるように (400,301,...)

今、私は次のようなすべての投稿 (リンクありとなし) に対して 1 つのモデルで立ち往生しています。

#
# 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 と検証の使用に関する適切なリソースを知っている場合は、リンクを教えてください。

4

1 に答える 1

0

レールでは、いつもと違うことをしていることに気付いたときはいつでも、それはおそらく間違っています。または、間違っていなければ、達成したいことを達成しようとする多くの作業を意味する可能性があります. 検証は通常、モデルに対して行われ、単純なルーティングに関係のないコードがコントローラーに存在することはありません。したがって、これに対処する正しい方法は、検証コードをモデルに入れることです。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 に答える