Rails index action always returns null - ruby-on-rails-3

So I am having an issue where I have this index action that is supposed to return json, but in the browser I am always getting a null response.
Controller
class Admin::Groups::UsersController < Admin::GroupsController
def index
#user_groups = Group.includes(:group_type, :users).where("group_types.group_type_name = ?", 'Users').order("groups.group_name ASC")
render json: #user_groups.to_json(:include => [:group_type, :users], :methods => :enabled)
end
def show
#user_group = Group.includes(:group_type, :users).where("group_types.group_type_name = ?", 'Users').find_by_id(params[:id])
render json: #user_group.to_json(:include => [:group_type, :users], :methods => :enabled)
end
end
Route file
namespace :admin do
namespace :groups do
resources :users, only: [:index, :show] do
get 'enabled', :on => :collection
get 'disabled', :on => :collection
end
end
end
Output of rake routes
admin_groups_users GET /admin/groups/users(.:format) admin/groups/users#index
What is really throwing me off is that when I run the same code that is inside the index action in the rails console, it is outputting exactly what I expected. Also the show action works fine. And just for testing, I added a new route that I just called index2 and copied + pasted the code from the index action into index2 and I got the correct output in the browser.
So it has to be something to do with my route, but I'm not sure what it is?
Edit 1: Add entire output of rake routes
enabled_admin_accounts GET /admin/accounts/enabled(.:format) admin/accounts#enabled
disabled_admin_accounts GET /admin/accounts/disabled(.:format) admin/accounts#disabled
account_owners_admin_accounts GET /admin/accounts/account_owners(.:format) admin/accounts#account_owners
admin_accounts GET /admin/accounts(.:format) admin/accounts#index
admin_account GET /admin/accounts/:id(.:format) admin/accounts#show
enabled_admin_users GET /admin/users/enabled(.:format) admin/users#enabled
disabled_admin_users GET /admin/users/disabled(.:format) admin/users#disabled
admin_users GET /admin/users(.:format) admin/users#index
admin_user GET /admin/users/:id(.:format) admin/users#show
enabled_admin_owners GET /admin/owners/enabled(.:format) admin/owners#enabled
disabled_admin_owners GET /admin/owners/disabled(.:format) admin/owners#disabled
currencies_admin_owner GET /admin/owners/:id/currencies(.:format) admin/owners#currencies
admin_owners GET /admin/owners(.:format) admin/owners#index
admin_owner GET /admin/owners/:id(.:format) admin/owners#show
enabled_admin_counterparties GET /admin/counterparties/enabled(.:format) admin/counterparties#enabled
disabled_admin_counterparties GET /admin/counterparties/disabled(.:format) admin/counterparties#disabled
admin_counterparties GET /admin/counterparties(.:format) admin/counterparties#index
admin_counterparty GET /admin/counterparties/:id(.:format) admin/counterparties#show
enabled_admin_venues GET /admin/venues/enabled(.:format) admin/venues#enabled
disabled_admin_venues GET /admin/venues/disabled(.:format) admin/venues#disabled
admin_venues GET /admin/venues(.:format) admin/venues#index
admin_venue GET /admin/venues/:id(.:format) admin/venues#show
enabled_admin_custody_banks GET /admin/custody_banks/enabled(.:format) admin/custody_banks#enabled
disabled_admin_custody_banks GET /admin/custody_banks/disabled(.:format) admin/custody_banks#disabled
admin_custody_banks GET /admin/custody_banks(.:format) admin/custody_banks#index
admin_custody_bank GET /admin/custody_banks/:id(.:format) admin/custody_banks#show
enabled_admin_client_currencies GET /admin/client_currencies/enabled(.:format) admin/client_currencies#enabled
disabled_admin_client_currencies GET /admin/client_currencies/disabled(.:format) admin/client_currencies#disabled
admin_client_currencies GET /admin/client_currencies(.:format) admin/client_currencies#index
admin_client_currency GET /admin/client_currencies/:id(.:format) admin/client_currencies#show
admin_currencies /admin/currencies(.:format) admin/client_currencies#index
admin_all_currencies /admin/all_currencies(.:format) admin/currencies#index
enabled_admin_groups GET /admin/groups/enabled(.:format) admin/groups#enabled
disabled_admin_groups GET /admin/groups/disabled(.:format) admin/groups#disabled
admin_groups GET /admin/groups(.:format) admin/groups#index
admin_group GET /admin/groups/:id(.:format) admin/groups#show
enabled_admin_groups_accounts GET /admin/groups/accounts/enabled(.:format) admin/groups/accounts#enabled
disabled_admin_groups_accounts GET /admin/groups/accounts/disabled(.:format) admin/groups/accounts#disabled
admin_groups_accounts GET /admin/groups/accounts(.:format) admin/groups/accounts#index
admin_groups_account GET /admin/groups/accounts/:id(.:format) admin/groups/accounts#show
enabled_admin_groups_account_owners GET /admin/groups/account_owners/enabled(.:format) admin/groups/account_owners#enabled
disabled_admin_groups_account_owners GET /admin/groups/account_owners/disabled(.:format) admin/groups/account_owners#disabled
admin_groups_account_owners GET /admin/groups/account_owners(.:format) admin/groups/account_owners#index
admin_groups_account_owner GET /admin/groups/account_owners/:id(.:format) admin/groups/account_owners#show
enabled_admin_groups_users GET /admin/groups/users/enabled(.:format) admin/groups/users#enabled
disabled_admin_groups_users GET /admin/groups/users/disabled(.:format) admin/groups/users#disabled
admin_groups_users GET /admin/groups/users(.:format) admin/groups/users#index
admin_groups_user GET /admin/groups/users/:id(.:format) admin/groups/users#show
enabled_admin_groups_counterparties GET /admin/groups/counterparties/enabled(.:format) admin/groups/counterparties#enabled
disabled_admin_groups_counterparties GET /admin/groups/counterparties/disabled(.:format) admin/groups/counterparties#disabled
admin_groups_counterparties GET /admin/groups/counterparties(.:format) admin/groups/counterparties#index
admin_groups_counterparty GET /admin/groups/counterparties/:id(.:format) admin/groups/counterparties#show
enabled_admin_groups_currencies GET /admin/groups/currencies/enabled(.:format) admin/groups/currencies#enabled
disabled_admin_groups_currencies GET /admin/groups/currencies/disabled(.:format) admin/groups/currencies#disabled
admin_groups_currencies GET /admin/groups/currencies(.:format) admin/groups/currencies#index
admin_groups_currency GET /admin/groups/currencies/:id(.:format) admin/groups/currencies#show
root / trades#index
jasminerice /jasmine Jasminerice::Engine

You need to move this route further down the route list.
admin_group GET /admin/groups/:id(.:format) admin/groups#show
The route list is searched in-order. /admin/groups/users is matching this route with :id equal to users.

render is either in the form
render :json => #user_groups
in which it calls to_json for you and it cannot pass arguments, or you can do this:
format.json { render #user_groups.to_json(:include => [:group_type, :users], :methods => :enabled) }
If you always want to return json no matter what format is, then just get rid of the json: thing:
render #user_groups.to_json(:include => [:group_type, :users], :methods => :enabled)

Please change your routes to this and check
namespace :admin do
namespace :groups do
resources :users, :only => [:index,:show],:collection => {:enabled => :get,:disabled => :get}
end
end

Related

Why isn't my search method working in Ruby on Rails?

In my Ruby on Rails application, I have a cinema system and am trying to return the screen a showing is in when a user searches for the showing.
To display the search drop down I am using this code in my _application.html.erb:
<%= render( :partial => '/screen_lookup', :locals => {:showings => #showings = Showing.all, :my_path => '/screens/display_screens_by_showing' })%>
Which renders the search from the _screen_lookup.html.erb:
<%= form_tag my_path, :method=>'post', :multipart => true do %>
<%= select_tag ('showings_id'),
options_from_collection_for_select(#showings, :id, :showing_times, 0 ),
:prompt => "Showings" %>
<%= submit_tag 'Search' %>
<% end %>
And uses the display_screens_by_showing in the screens_controller:
def display_screens_by_showing
#screens = Screen.showing_search(params[:showing_id])
if #screens.empty?
# assign a warning message to the flash hash to be displayed in
# the div "feedback-top"
flash.now[:alert] = "There are no films of that genre."
# return all products, in alphabetical order
#screens = Screen.all
end
render :action => "index"
end
And this searches using the method in the screen.rb model:
def self.showing_search(showing_id)
screen = Showing.where("id = ?", showing_id).screen_id
self.where("id = ?", screen)
end
Now, the problem I am having is that because a showing belongs_to a screen, and a screen has_many showings, I need to be able to search for the showing, and store that showing's screen_id in a variable to search for the screen that showing is in with, which I have tried doing in the model:
screen = Showing.where("id = ?", showing_id).screen_id
self.where("id = ?", screen)
But the error I am getting is:
NoMethodError in ScreensController#display_screens_by_showing
undefined method `screen_id' for #<ActiveRecord::Relation []>
These are the model relationships:
showing.rb:
class Showing < ActiveRecord::Base
belongs_to :screen
end
screen.rb:
class Screen < ActiveRecord::Base
has_many :showings
end
What code will get my search working?
The problem is that where doesn't return a record, it returns a relation that can be enumerated or chained, instead you want to use find or find_by to return a single record, which is kind equivalent to where + first
screen = Showing.find(showing_id).screen_id
which is sort of like doing
screen = Showing.where(id: showing_id).first.screen_id
If you want to pass a hash you can use find_by which will be like this
screen = Showing.find_by(id: showing_id).screen_id
PS:
I'm not sure what you're doing exactly, but i think those two lines can be merged into a single query ( not sure what it should be returning, but I'm assuming a screen )
def self.showing_search(showing_id)
Showing.find(showing_id).screen
end

How to make tests with find and date conditions?

I'm trying to develop some tests for a method which is responsible for retrieve some users created after some date. I don't know how to mock tests for it. The method is the following:
def user_list
render :nothing => true, :status => 422 if params[:time_param].blank?
time = Time.parse(params[:time_param])
#users = User.find(:all, :select => 'id, login, email',
:conditions => ["created_at > ?", time])
render :json => { :users => #users }
end
end
This is my spec:
describe UsersController do
context "when receiving time parameter" do
before (:each) do
#time_param = "2013-01-25 00:01:00"
user1 = mock_model(User, :created_at => Time.parse('2013-01-25 00:00:00'))
user2 = mock_model(User, :created_at => Time.parse('2013-01-25 00:01:00'))
user3 = mock_model(User, :created_at => Time.parse('2013-01-25 00:02:00'))
#users = []
#users << user1 << user2 << user3
end
it "should retrieve crimes after 00:01:00 time" do
User.stub(:find).with(:all, :select => 'id, login, email').and_return(#users)
get :user_list, { :time_param => #time_param }
JSON.parse(response.body)["users"].size.should eq 1
end
end
end
The problem is that it always returns all users despite of returning just one. (the last one). Where am I mistaking?
Help me =)
You are not testing what you have to test there, on a controller spec you only need to test that the method that you want is called with the parameters that you want, in your case, you have to test that the User model receives :find with parameters :all, :select => 'id, login, email', :conditions => ["created_at > ?", time] (with time the value that should be there.
Also, that logic does not belong to the controller, you should have a class method on User, something like select_for_json(date) to wrap around that find method (you can find a better name for it)
Then your controller becomes:
def user_list
render :nothing => true, :status => 422 if params[:time_param].blank?
time = Time.parse(params[:time_param])
#users = User.select_for_json(time)
render :json => { :users => #users }
end
your spec would be
before(:each) do
#users = mock(:users)
#time_param = "2013-01-25 00:01:00"
end
it "retrieve users for json" do
User.should_receive(:select_for_json).once.with(#time).and_return(#users)
get :user_list, { :time_param => #time }
assigns(:users).should == #users
end
that way you are sure that your action does what it does and the spec is A LOT faster since you are not creating users
then you can test that method on the model specs, there you have to create some users, invoke that method and check the users returned (don't stub/mock anything on your model spec)
Your stub call is telling find to ignore what it thought it was supposed to do and return #users instead. It will not attempt to match the conditions.
Unfortunately, to do your test I think you're going to have to allow the find to execute through your database which means you can't use mock_models. You probably will want to do either User.create(...) or FactoryGirl.create(:user) (or some other factory / fixture).
Of course doing it this way, you may hit MassAssignment issues if you use attr_accessible or attr_protected, but those are easy enough to stub out.
I hope that helps.

Rails 3 - Merge query options

I have this method form a Rails 2.3.4 app:
def self.find_all_colored(query, options={})
finder_options = {:conditions => "color = #{query}"}.merge(options)
Car.find(:all, finder_options)
end
With which I can do:
Car.find_all_colored("red", :limit => 5)
But I am having a really bad time trying to get that to work in Rails 3.1.1, by now I can make it work but without the .merge(options), if I add that part:
def self.find_all_colored(query, options={})
Car.where("color = #{query}").merge(options)
end
I get this error:
undefined method `default_scoped?' for {:limit=>5}:Hash
I've googled and searched in stackoverflow.com but no luck...thanks!
Try the following:
def self.find_all_colored(query, options={})
self.all({:conditions => {:color => query}}.merge(options))
end

API Code Not Rendering JSON From Controller Properly From Heroku

I am trying to write api code that utilizes the JSON rendered from the controller. I was able to successfully get my desired results locally, but when I push to Heroku parts of my JSON is not rendered correctly.
To put in context, I am trying to create a nested JSON with meal information (name, id, etc) and photo urls. Locally the photo urls render correctly in the JSON. However, on Heroku the photo urls show up as null. On Heroku, I have also tested just rendering the url JSON alone and it is getting the urls correctly.
If you know why it is rendering correctly locally and not on Heroku please let me know. Thank you
I create my JSON the following way:
def api
#meals = Meal.all
#urls = Hash.new
#return_val = Array.new
#sorted_meals = Meal.select('meals.name as meal_name, meals.id as meal_id,
COALESCE(sum(meal_ratings.rating), 0) as meal_rating,
restaurants.id as restaurant_id, restaurants.name as restaurant_name').
joins('LEFT JOIN meal_ratings ON meals.id = meal_ratings.meal_id
LEFT JOIN restaurants ON restaurants.id = meals.restaurant_id').
group('meals.name, meals.id, restaurants.id, restaurants.name').
order('meal_rating DESC').all
#meals.each do |meal|
unless meal.meal_photos.empty?
#urls[meal.id] = {"thumb" => meal.meal_photos[0].photo.url(:thumb), "profile" => meal.meal_photos[0].photo.url(:profile)}
end
end
#sorted_meals.each do |meal|
#return_val.push("id" => meal.meal_id, "name" => meal.meal_name,
"rating" => meal.meal_rating, "restaurant" => meal.restaurant_name,
"restaurant_id" => meal.restaurant_id, "urls" => #urls[meal.meal_id])
end
respond_to do |format|
format.html # show.html.erb
format.json { render json: #return_val } # render json: #url render json: #meals
end
end
The problem was due to Postgres. When I query for a meal_id it returned a string and was not working as a hash key, so I was getting nil. After turning the id string into turn an int everything worked fine. Thanks to the help of Sena this has been resolved.

override to_xml to limit fields returned

using ruby 1.9.2 and rails 3, i would like to limit the fields returned when a record is accessed as json or xml (the only two formats allowed).
this very useful post introduced me to respond_with and i found somewhere online that a nice way to blanket allow/deny some fields is to override as_json or to_xml for the class and set :only or :except to limit fields.
example:
class Widget < ActiveRecord::Base
def as_json(options={})
super(:except => [:created_at, :updated_at])
end
def to_xml(options={})
super(:except => [:created_at, :updated_at])
end
end
class WidgetsController < ApplicationController
respond_to :json, :xml
def index
respond_with(#widgets = Widgets.all)
end
def show
respond_with(#widget = Widget.find(params[:id]))
end
end
this is exactly what i am looking for and works for json, but for xml "index" (GET /widgets.xml) it responds with an empty Widget array. if i remove the to_xml override i get the expected results. am i doing something wrong, and/or why does the Widgets.to_xml override affect the Array.to_xml result?
i can work around this by using
respond_with(#widgets = Widgets.all, :except => [:created_at, :updated_at])
but do not feel that is a very DRY method.
In your to_xml method, do the following:
def to_xml(options={})
options.merge!(:except => [:created_at, :updated_at])
super(options)
end
That should fix you up.