【问题标题】:Rails: Validate params before they are handled in controller?Rails:在控制器处理参数之前验证参数?
【发布时间】:2014-04-20 10:19:15
【问题描述】:

我正在制作一个 Rails 应用程序,用户可以在其中将 soundcloud 链接粘贴到输入字段中。然后,此链接被发送到我的post_controller 中的创建操作,并用于获取该歌曲的 JSON 文件。

# app/controllers/post_controller.rb

def create
  require 'open-uri'

  raw_link = params[:post][:link]

  raw_link.downcase.include? "soundcloud.com/"
  tmp_media_json = JSON.load(open("http://soundcloud.com/oembed?format=json&url=#{raw_link}"))
  if tmp_media_json['thumbnail_url']["placeholder"]
    tmp_media_json['thumbnail_url'] = JSON.load(open("http://soundcloud.com/oembed?format=json&url=#{tmp_media_json['author_url']}"))['thumbnail_url']
  end

  media_thumbnail = tmp_media_json['thumbnail_url'].gsub('t500x500.jpg', 't80x80.jpg')
  media_title = tmp_media_json['title']
  media_iframe = tmp_media_json['html']
  media_type = params[:post][:media_type]

  @post = Post.new(link: media_iframe, title: media_title, thumbnail: media_thumbnail, media_type: media_type)

  respond_to do |format|
    if @post.save
      format.js { render :file => "/pages/create_new_post.js.erb" }
      format.html { redirect_to @post, notice: 'Post was successfully created.' }
      format.json { render action: 'show', status: :created, location: @post }
    else
      format.html { render action: 'new' }
      format.json { render json: @post.errors, status: :unprocessable_entity }
    end
  end
end

Post 模型中,我正在尝试运行validates :link, presence: true,但问题是它似乎是在创建操作中的所有代码之后完成的。我希望在创建操作中的所有代码之前完成验证。 (因为如果没有有效的链接,创建操作中的代码将不起作用)。

我该怎么做或有更好的做法?

【问题讨论】:

标签: ruby-on-rails validation ruby-on-rails-4 actioncontroller


【解决方案1】:
class YourController < ApplicationController
    before_filter :my_filter
    before_filter :my_filter2, :except => [:index, :new, :create]
    def my_filter
     # your code gose here
    end
    def my_filter2
     # your code gose here
    end
........
end

【讨论】:

    【解决方案2】:

    您需要将 json 提取代码移出控制器并放入模型中。考虑单一职责原则(SRP):http://en.wikipedia.org/wiki/Single_responsibility_principle

    另外,这个问题有点令人困惑,因为您正在验证“链接”属性,该属性是从 soundcloud 加载 JSON 的结果,所以这种方式使您的问题无法实现。

    话虽如此,保持控制器精简

    # controller...
    def create
      @post = Post.new_from_link(params[:post][:link], params[:post][:media_type])
      @post.save
      ...render...
    
    end
    
    # post model...
    class Post < ActiveRecord::Base
      attr_accessor :raw_link, :raw_media_type
    
      def new_from_link(raw_link, raw_media_type)
        @raw_link = raw_link
        @raw_media_type = raw_media_type
      end
    
      def assign_soundcloud_attributes
        fetcher = SoundCloudFetcher.new(raw_link, raw_media_type).fetch
        self.link = fetcher.link
        self.media_type = fetcher.media_type
        self.media_thumbnail = fetcher.media_thumbnail
        self.media_iframe = fetcher.media_iframe
      end
    end
    
    class SoundCloudFetcher
      attr_accessor :link, :media_type, :media_thumbnail, :media_title, :media_iframe
    
      def self.initialize(raw_link, raw_media_type)
        @raw_link = raw_link
        @raw_media_type = raw_media_type
      end
    
      def fetch
        ...go get and set the data...
        return self
      end
    end 
    

    所以上面的代码是不完整的。它缺少对#assign_soundcloud_attributes 的实际调用。这种设计让您可以在想要拨打电话的地方四处走动。您可以将调用放在#new_from_link 中,也可以将其放在 before_validation 或 before_create 回调中,具体取决于您的需要。

    要解决这个问题的问题是,您是要验证传入的 raw_link,还是要验证从 soundcloud api 调用返回的链接。

    如果您要验证原始链接,请将对 #assign_soundcloud_attributes 的调用移至 before_create 回调。

    如果您要验证从 SoundCloud api 调用中检索到的实际链接属性,请将其放入 #new_from_link 或 #before_validation 回调中。

    【讨论】:

      【解决方案3】:

      您可以将 before_filter 与 rails_parms gem 一起使用。

      https://github.com/nicolasblanco/rails_param

      它是这样工作的:

      param! :q,           String, required: true
      param! :categories,  Array
      param! :sort,        String, default: "title"
      param! :order,       String, in: %w(asc desc), transform: :downcase, default: "asc"
      param! :price,       String, format: /[<\=>]\s*\$\d+/
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-07-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多