Why is my log showing a partial rendered twice Rails - ruby-on-rails-3

I want to show an easier example of the same thing:
Started GET "/greetings/new" for 127.0.0.1 at 2011-09-29 15:30:46 +0700
Processing by GreetingsController#new as JS
Board Load (0.6ms) SELECT "boards".* FROM "boards" WHERE "boards"."id" = 12 LIMIT 1
User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Upload Load (0.2ms) SELECT "uploads".* FROM "uploads" WHERE ("uploads".uploadable_id = 1 AND "uploads".uploadable_type = 'User') LIMIT 1
Rendered greetings/_greeting_form.html.erb (108.9ms)
Rendered greetings/_greeting_form.html.erb (4.1ms)
Rendered greetings/new.js.erb (116.9ms)
Completed 200 OK in 302ms (Views: 126.5ms | ActiveRecord: 1.7ms)
The log shows that the _greeting_form.html.erb is being rendered twice. The partial is rendered with an Ajax call to the controller.
Controller:
def new
#greeting = Greeting.new
#user = current_user || User.new
respond_to do |format|
format.js {render :action => 'new'}
end
end
new.js.erb
if($('#boxGreeting').length == 0){
$('#buttons').after($(" <%=escape_javascript(render 'greeting_form', :user => #user, :greeting => #greeting) %>").fadeIn('fast'));
}
else
{
$('#boxGreeting').replaceWith("<%=escape_javascript(render 'greeting_form', :user =>#user, :greeting => #greeting)%>");
}

You are calling render 'greeting_form' twice in your new.js.erb. If you look into the output .js file in your browser you will see that the partial appears twice.
The browser will later evaluate your javascript if-clause and use either the first or the second of the pre-rendered "greeting_form" partials.
You can avoid parsing it twice by assigning the render result to a variable and then use this variable within the if or else part:
var greeting_form = " <%=escape_javascript(render 'greeting_form', :user => #user, :greeting => #greeting) %>";
if($('#boxGreeting').length == 0) {
$('#buttons').after($(greeting_form).fadeIn('fast'));
}
else {
$('#boxGreeting').replaceWith(greeting_form);
}

Related

Thinking Sphinx searching search across all models

i've implemented search for induvidual models and it works.
Now i have my home page which has a form that has fields from several models of my application but searching one field at a time doesn't yield any result on the home page although i can see the query....(searching for tv_show name)
Parameters: {"utf8"=>"✓", "name"=>"count", "broadcast_date_from"=>"", "broadcast_date_to"=>"", "gender"=>"", "organization_id"=>"", "position_id"=>"", "alignment"=>"", "commit"=>"Generate"}
Sphinx Query (1.0ms) SELECT * FROM `episode_core`, `organization_core`, `person_core`, `position_core`, `profession_core`, `segment_core`, `tv_show_core` WHERE MATCH('*count*') AND `sphinx_deleted` = 0 ORDER BY `last_name` ASC, first_name ASC LIMIT 0, 20
Sphinx Found 0 results
Rendered home/index.html.erb within layouts/home (3.0ms)
Completed 200 OK in 13ms (Views: 12.9ms | ActiveRecord: 0.0ms)
when search the model tv_show i have a result.
Parameters: {"utf8"=>"✓", "name"=>"count", "channel"=>"", "starting_time"=>"", "ending_time"=>"", "commit"=>"Search"}
Sphinx Query (0.9ms) SELECT * FROM `tv_show_core` WHERE MATCH('*count*') AND `sphinx_deleted` = 0 ORDER BY `tv_name` ASC LIMIT 0, 20
Sphinx Found 2 results
TvShow Load (0.5ms) SELECT "tv_shows".* FROM "tv_shows" WHERE "tv_shows"."id" IN (9, 4)
Rendered tv_shows/index.html.erb within layouts/application (7.5ms)
Rendered tv_shows/_search.html.erb (0.9ms)
Completed 200 OK in 68ms (Views: 66.7ms | ActiveRecord: 0.5ms)
So why is there a difference?
global search no result
#results = ThinkingSphinx.search.search "#{params[:name]} ",
:star => /[\w#:]+/u,
:order => 'last_name ASC, first_name ASC',
:page => params[:page],
:per_page => 20
model search return results
#tv_shows = TvShow.search "#{params[:name]} #{params[:channel]} ",
:star => /[\w#:]+/u,
:order => 'tv_name ASC',
:page => params[:page],
:per_page => 20
UPDATE
ok removing the :order => 'last_name ASC, first_name ASC', get me somewhere.
Have another question
how do you make it query a specific model depending on the field used in the form?
Parameters: {"utf8"=>"✓", "name"=>"count", "broadcast_date_from"=>"", "broadcast_date_to"=>"", "gender"=>"", "organization_id"=>"", "position_id"=>"", "alignment"=>"", "commit"=>"Generate"}
Profession Load (0.9ms) SELECT "professions".* FROM "professions" ORDER BY name
Organization Load (2.5ms) SELECT "organizations".* FROM "organizations" ORDER BY name
Position Load (2.0ms) SELECT "positions".* FROM "positions" ORDER BY name
Sphinx Query (1.7ms) SELECT * FROM `episode_core`, `episode_delta`, `organization_core`, `organization_delta`, `person_core`, `person_delta`, `position_core`, `position_delta`, `profession_core`, `profession_delta`, `segment_core`, `segment_delta`, `tv_show_core`, `tv_show_delta` WHERE MATCH('*count*') AND `sphinx_deleted` = 0 LIMIT 0, 20
Sphinx Found 4 results
Organization Load (0.5ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" IN (109)
Position Load (0.4ms) SELECT "positions".* FROM "positions" WHERE "positions"."id" IN (164)
TvShow Load (0.4ms) SELECT "tv_shows".* FROM "tv_shows" WHERE "tv_shows"."id" IN (4, 9)
Here i am just using the tv_show field which refer to the TvShow model.
Adding a conditon is not helping....:condition => {:tv_name => params[:name]}
any insight appreciated.
Response(just in case)
Needed to add in the global search view :
<% for result in #results %>
<% if result.class.name == "Organization" %>
<%= render :partial => "organizations/result", :locals => { :result => result } %>
<% elsif result.class.name == "Position" %>
<%= render :partial => "positions/result", :locals => { :result => result } %>
<% elsif result.class.name == "TvShow" %>
<%= render :partial => "tv_shows/result", :locals => { :result => result } %>
<% end %>
<% end %>
and create partial ( _result.html.erb ) for each model in view folder to print the different fields (The partials are optional).

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 Load Edit view for a selected row from a DataTable

I have been struggling with this for a while. As well as some specific help I would be grateful for some pointers how I may fill some of the gaps in my knowledge. BTW I am new to Rails and web development.
I have used DataTables to display a table records and have some code which shows me the id of the row selected by the user. From within my index view I want to use that row id to load the edit view for that data row. My .js code is as follows:
$(document).ready(function() {
/* Init the table */
TableTools.DEFAULTS.aButtons = [];
oTable = $("#highways").dataTable({
sPaginationType: "full_numbers",
bJQueryUI: true,
"bProcessing": true,
"bServerSide": true,
iDisplayLength: 25,
sAjaxSource: $('#highways').data('source'),
"aoColumns": [
null,
null,
null,
null,
null
],
"sDom": 'T<"clear">lfrtip',
"oTableTools": {
"sRowSelect": "single",
"fnRowSelected": function ( node ) {
var oTT = TableTools.fnGetInstance('highways');
var aData = oTT.fnGetSelectedData();
var n = '/highways/' + aData[0][4] + '/edit'
alert(n);
var jqxhr = $.get(n, function() {
alert("success");
})
}
},
});
} );
The development log shows:
Started GET "/highways/8/edit" for 127.0.0.1 at 2012-08-21 07:57:14 +1000
Processing by HighwaysController#edit as /
Parameters: {"id"=>"8"}
[1m[35mHighway Load (0.3ms)[0m SELECT highways.* FROM highways WHERE highways.id >= 8 LIMIT 1
Highway BARKLY HIGHWAY
Rendered highways/_form.html.erb (67.1ms)
Rendered highways/edit.html.erb within layouts/highways (258.5ms)
Completed 200 OK in 276ms (Views: 274.6ms | ActiveRecord: 0.3ms)
I have tried various things in the controller code, and in some cases the log says the edit view has been renedered but it does not show in the browser. Current controller code:
class HighwaysController < ApplicationController
respond_to :html, :json
def index
# #highways = Highway.all
# logger.debug "Highway Count: #{#highways.size}"
respond_to do |format|
format.html
format.json { render json: HighwaysDatatable.new(view_context) }
end
end
def edit
# logger.debug "Edit (render :layout => false) Highway ID #{params[:id]}"
#highway = Highway.find(params[:id])
logger.debug "Highway #{#highway.name}"
# render
respond_to do |format|
format.html
format.json { render json: HighwaysDatatable.edit(view_context) }
end
Is the $.get returning JSON ?
I have also tried a different approach. I have a link_to in the index view:
<div id ="highway_edit" >
<% #n = 11.to_s %>
<%= link_to "Edit 2", edit_highway_path(#n), :remote => true %>
</div>
This hard coded version works but I could not find a way to modify that link from within the javascript code so that it reflected the selected row id, or to call a function which would return the row id into the variable #n.
I realize that there must be some fundamentals I am missing so some suggested starting points for my education would be appreciated. I have read many other related questions but do not have enough knowledge to extract what I need.
PS I see that DataTables has an Editor feature which does pretty much what I want to achieve in the long run, but it is not 'Rails ready'.
Thanks!
EDIT:
In preparing this question I did not properly restore my code to the stage I wanted to discuss. So I have changed the controller code and the subsequent development log. So instead of a template error the problem is that the view is not rendered.
EDIT
I have proceeded with this problem and now have a result. I added a new div (class of 'result') to the top of my index view and changed my js code as follows:
var n = '/highways/' + aData[0][4] + '/edit'
$.get(n, function(data) {
$('.result').html(data);
and the edit view is rendered in that div. The result is ugly as it pushes the table down and doubles up the DataTable headers and footer. But at least it renders. I don't understand why this works when both ways go via the Edit method in the controller. I can now work on the cosmetics, or better still have the edit view appear as a modal overlay.
I would prefer to be able to click (or preferably double-click) a row and the edit view for that row be loaded. I will continue to look to do it that way. In the meantime I have added a link to the view:
<div id="EditLink">
<%= link_to "Edit Highway", :controller => :highways, :action => :edit, :id => 1 %>
</div>
and have the following code in the call back function:
"oTableTools": {
"sRowSelect": "single",
"fnRowSelected": function(node) {
var oTT = TableTools.fnGetInstance('highways');
var aData = oTT.fnGetSelectedData();
$("div#EditLink a").attr('href','/highways/' + aData[0][4] + '/edit')
}
},
which modifies the link based on the id of the selected row. Using this method the user has to know to first select a row and then click the link. If they do not first select a row they will go to the default (id = 1). You have to make sure that such an id exists in the table.

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.

Refactor this controller?

class ArticlesController < ApplicationController
def index
#articles = Article.by_popularity
if params[:category] == 'popular'
#articles = #articles.by_popularity
end
if params[:category] == 'recent'
#articles = #articles.by_recent
end
if params[:category] == 'local'
index_by_local and return
end
if params[:genre]
index_by_genre and return
end
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #articles }
end
end
def index_by_local
# 10 lines of code here
render :template => 'articles/index_by_local'
end
def index_by_genre
# ANOTHER 10 lines of code here
render :template => 'articles/index_by_genre'
end
end
As you can see from above. My controller is not exactly thin. What its doing is, depending on the params that were passed, it interacts with the model to filter out records.
And if params[:local] or params[:genre] was passed. Then it calls its own methods respectively (def index_by_local and def index_by_genre) to do further processing. These methods also load their own template, instead of index.html.erb.
Is this quite typical for a controller to look? Or should I be refactoring this somehow?
We can move the first few lines into the model(article.rb):
def get_by_category(category)
# Return articles based on the category.
end
In this way we can completely test the article fetching logic using unit tests.
In general move all the code related to fetching records inside model.
Controllers in general
should authorize the user
get records using the params and assign them to instance variables
[These must typically be function
calls to model]
Render or redirect
I would define scopes for each of the collections you want to use.
class Article < ActiveRecord::Base
...
scope :popular, where("articles.popular = ?", true) # or whatever you need
scope :recent, where(...)
scope :by_genre, where(...)
scope :local, where(...)
...
def self.filtered(filter)
case filter
when 'popular'
Article.popular, 'articles/index'
when 'recent'
Article.recent, 'articles/index'
when 'genre'
Article.by_genre, 'articles/index_by_genre'
when 'local'
Article.local, 'articles/index_by_local'
else
raise "Unknown Filter"
end
end
end
Then in your controller action, something like this:
def index
#articles, template = Article.filtered(params[:category] || params[:genre])
respond_to do |format|
format.html { render :template => template }
format.xml { render :xml => #articles }
end
end