我正在创建一个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
,但问题是它似乎是在创建操作中的所有代码之后完成的。我希望在create action中的所有代码之前完成验证。 (因为如果没有有效的链接,创建操作中的代码将无效)。
我该怎么做或有更好的做法?
答案 0 :(得分:0)
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
答案 1 :(得分:0)
您需要将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回调中。
答案 2 :(得分:0)
你可以使用带有 rails_parms gem的before_filter。
请参阅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+/