Sign in through GitHub

Please read for an updated status on RailsCasts:

Learn more or hide this

Antek Drzewiecki's Profile

GitHub User: Antek-drzewiecki

Comments by Antek Drzewiecki

Avatar

I prefere Earle Clubbs method. Besides turn off cache classes when you are using spork with guard.

http://www.avenue80.com/tiny-tip-spork-not-reloading-classes/

pengpenglin's method didnt work quite well with model validations and cache counters.

Avatar

In my previous post, forget about Capibara.

I got a sample how you could test some controllers..
In my setup I use; factorygirl and RSpec.

Ruby
require 'spec_helper'
module Api
  module V1
    describe UserSessionsController do
      render_views
      describe "authenticate" do
        it "authenticates correctly" do         
          user = FactoryGirl.create(:user)          
          post :create, :email => user.email, :password => user.password, :format => "json"  
          user.reload
          response.cookies['user_token'].should eq(user.user_token)
          response.should be_success
          body = JSON.parse(response.body)
          body['id'].should eq(user.id)
          body['email'].should eq(user.email)
          body['user_token'].should eq(user.user_token)
          body['password'].should equal nil
          body['profile'].should_not be nil
          
        end
        it "should return a json user"
          user = FactoryGirl.create(:user) #this user
          @request.cookies['user_token'] = user.user_token #  if you need an auth cookie..
          get :show, :id => user.id, :format => "json"
          response.should be_success
          body = JSON.parse(response.body)
          body.should have(1).user #test if only one root object is returned (sometimes you dont want to have a json root..)
          body[0].should have_key("user") #test root key...
          body[0]['user'].should have_key("id")
          body[0]['user'].should have_key("email")
          body[0]['user'].should have_key("friends")
          body[0]['user'].should have_key("profile") #test if the user has an associated profile
          body[0]['user'].should have_key("updated_at")
          body[0]['user']['profile'].should have(1).profile # test that the user returns only 1 profile.
          body[0]['user']['friends'].should have(3).friends #test that the user has 3 friends
        end
      end
    end
  end
end

I hope this helps you..

Avatar

Hey Zolzaya,
I did some research myself. I think i will try to split my controller and response tests with Capibara gem. What I test in my controllers are the controller logic. I still need to get started with testing on my json responses. Ill give you a update...

Ruby
require 'spec_helper'
module Api
  module V1
    describe UserSessionsController do
      describe "authenticate" do
        it "authenticates correctly" do         
          user = FactoryGirl.create(:user)          
          post :create, :login => user.email, :password => user.password, :format => "json"    
          response.should be_success
        end
      
      describe "fail authentication" do 
      end
      
      describe "logout" do 
      end
      
      
    end
  end
end

One thing i have to use :format => "json" to get json responses, it would be great if it went automatically.

One more thing check RABL git how to test your RABL responses.

https://github.com/nesquena/rabl/wiki/Testing-with-rspec

Here you go mate ;)

Avatar

Ok I figured it out after a weekend relaxing :p
You can put in your rspec:

ruby
module Api
  module V1
  end
end

This will perfectly work. In my other attempts before the weekend i placed do behind V1 and Api, that will just not work. :)

Avatar

By the way API::V1::ProductsController will not just work.

Avatar

I dont know how about you guys but i cant seem to get my tests to work.
How do you guys write these tests if your controller is nested inside the modules?

ruby
require 'spec_helper'
namespace :api do
  namespace :v1 do
    describe ProductsController do

      describe "GET 'index'" do
        it "returns http success" do
          get 'index'
          response.should be_success
        end
      end
    end    
  end
end
console
Failures:

  1) ProductsController GET 'index' returns http success
     Failure/Error: get 'index'
     ActionController::RoutingError:
       No route matches {:controller=>"products"}
     # ./spec/controllers/api/v1/products_controller_spec.rb:10:in `block (5 levels) in <top (required)>'

Obviously because the correct route should be:
{:action=>"index", :controller=>"api/v1/products"}

Avatar

Hi Ryan, lately I've seen a lots of development railscasts for rails API's. What are the best practices to test API's and versions? Because you don't want to break anything down if you implement new features, change the json format later on. What i would like to know is how you guys test your json api's input and output and even with versioning. Maybe this would be a good idea for a railscast.

Thanks

Avatar

Nice advice to put it in a initializer.
I also came across this solution a time ago. This works for some cases.
When you have a large website 10 or more locales its not handy to define a fallback for each locale. The point is you have to define the fallbacks static.

I am using an Article to explain my problem but a more suitable case is when you have an Festival. An Festival is held in a Country and has a language that is the base language for the Festival. The Festival is held in England so the organisation enters the data in the English language. The organisation decides also to translate the translate the website in the WK language. Now a German guys enters the website, what i dont want is that the website shows the Festival in the next best fallback language but the language its originally created with. Because a Festival can also be entered in the WK language(original) and English language (translation) then a German user needs to see the Festival information in WK.

Then static fallbacks wont help me..

Avatar

Hello guys and Ryan,

I was having a great challenge with Globalize3 regarding translating models on a website. Globalize3 relies on models created by a base locale set by I18n.locale or config.i18n.default_locale. Now lets have this situation when video above has three locales, WK, DE and EN (EN set as default). I have my fallback set to the en locale.

When I enter articles in english all goes fine, all the entries are now English for all locales. But for example when i try to make an article in WK language only, Globalize wont fall back to that language when the user browses the English or German language. For example when I view the page in German it still falls back to the English locale which is not set. Any suggestions how to fall back to the locale in which the Model is originally created when other locales are not set?

So my goal was; when a Article is created in a locale (WK) other then the default_locale (EN), the application needs to show that locale (WK) in the article as fallback locale. Even when i enter a translation for the default locale (EN) and the user requests the page in German (DE) the article is shown in the (WK) locale.

What i did is create an base_locale attribute to the Article model and tried overriding the read_attributes globalize uses. Here is some code

ruby
class Language < ActiveRecord::Base
attr_accessible :locale, :name
end


class Article < ActiveRecord::Base 

translates :title, :description, :fallbacks_for_empty_translations => true
attr_accessible :title, :description :base_locale_sym
belongs_to :base_locale, :class_name => "Language", :foreign_key => "base_locale_id"
before_save :set_base_locale_cache
def set_base_locale_cache
    if self.base_locale_id_changed?
      unless self.base_locale.blank?
        #sets the base locale cache for the created Article
        #i dont want to query Article.base_locale each time...
        self.base_locale_sym = Language.find(self.base_locale_id).locale
      else
        self.base_locale_sym = ""
      end
    end
  end

def read_attribute(name, options = {})
    #when the translated_locales does not include the i18n.locale try to show the model in the locale in which the Article was first created.
    unless self.translated_locales.include? I18n.locale.to_sym
      #merge the options hash
      options.merge(:locale => self.base_locale_sym)
    end
    super(name,options)
  end

end

This idea worked quite fine, but i had really issues with updating and generating models. Maybe someone got a better idea?

I couldn't figure out this puzzle so i stopped it 3 months ago. Since this railscast is about globalize, I thought maybe we can solve it..

Avatar

Anyone experienced an issue when running rvmsudo, that the script hangs at a password prompt that can not be entered?

ruby
Lets say this task: 
task :export, :roles => :app do
    run "cd #{release_path} && rvmsudo bundle exec foreman export upstart"
 end

Then rvmsudo will hang at [sudo] password for, you wont be able to enter a password.

I solved this issue by executing a random sudo command in front of the rvmsudo command.. For example sudo "whoami". But i wonder if there is a clean solution.

Also anyone experienced an issue that they can not restart their services trough rvmsudo? For example rvmsudo restart #{application}" throws /usr/bin/env: restart: No such file or directory

Avatar

I'm wondering, what would be a good meganism to ensure the user received the message? Im sure in some cases its important that the application is aware that the user received the message.

Probably not with a hidden form or something.

Avatar

Ryan what is the advantage of Private_pub compared to adding a key/ pass combination to model channels like this?
( And you have to listen to a channel like "/chatroom/new/room_key/room_pass/" )

ruby
class Chatroom < ActiveRecord::Base
before_create do |chatroom|
    generate_hex_token(:room_key)
    generate_token(:room_password)
  end
  def generate_token(column)
    begin
      self[column] = SecureRandom.base64.tr("+/=*", "-_")
    end while Chatroom.exists?(column => self[column])
  end
  
  def generate_hex_token(column)
    begin
      self[column] = SecureRandom.hex(4).tr("+/", "-_")
    end while Chatroom.exists?(column => self[column])
  end
end
Avatar

I figured it out... I believe this is more of a hack but it could be usefull for others.
You can't render two views. So what i did was....

ruby
respond_to do |format|
format.js 
format.json  { 
     render_to_string "message/create.js.erb", :layout => false
     render :json => @chatmessage, :status => :created 
}
end

Now both the javascript will get rendered (empty string) and json will be rendered properly..
Is there a more elegant solution?

Avatar

How would you force the rendering of the create.js file as well on receiving a JSON message ( Among a JSON messge)?

Avatar

How would you add search for category name with a text_field instead of id ?

products = Product.include(:category).order......
products = products.where("categories.name like ?", "%bla bla bla%")

Something like this? I know i can make category name an auto complete text search Railscasts #102 Auto-Complete Association (revised) like and just pass the category id.. Just looking for alternative ways..

Avatar

You can also use this following line to make the error messages more personal..

ruby
<h2><%= pluralize(target.errors.count, "error") %> prohibited this <%= target.human_name.downcase %> from being saved:</h2>

And if you are unhappy with your model name you can always add an i18n translation to the model name!