0

I'm making a rails app where user can paste a soundcloud link in an input field. Then, this link is sent to the create action in my post_controller and used to get the JSON file for that song.

# 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

In the Post model, I'm trying to run validates :link, presence: true, but the problem is that it seems to be done after all the code in the create action. I want the validation to be done before all the code in the create action. (Since if there isn't a valid link, the code in the create action won't work).

How can I do this or is there a better practice?

ekremkaraca
  • 1,453
  • 2
  • 18
  • 37
allegutta
  • 5,626
  • 10
  • 38
  • 56

3 Answers3

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
tas
  • 472
  • 3
  • 6
0

You need to move the json fetching code out of the controller and into a model. Think Single Responsibility Principle(SRP): http://en.wikipedia.org/wiki/Single_responsibility_principle

Also, This question is slightly confusing because you are validating the "link" attribute which is the result of the JSON load from soundcloud, so this kind of makes your question impossible to achieve.

That being said, keep the controller lean

# 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 

So the code above is not complete. Its missing the actual call to #assign_soundcloud_attributes. This design lets you move around where you want to do the call. You can place the call in #new_from_link, or you can place it in a before_validation or before_create callback, depending on your needs.

The question to clear this up is are you intending to validate the raw_link thats passed in, or do you want to validate the link that comes back from the soundcloud api call.

If you are validating the raw link, move the call to #assign_soundcloud_attributes to a before_create callback.

If you are validating the actual link attribute that is retrieved from the SoundCloud api call, then put it in the #new_from_link or #before_validation callback.

Peter P.
  • 3,221
  • 2
  • 25
  • 31
0

You can use a before_filter with rails_parms gem.

See https://github.com/nicolasblanco/rails_param

It works like this:

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+/
Antzi
  • 12,831
  • 7
  • 48
  • 74