Rails3: not render view if no record found - ruby-on-rails

Here's my controller method
def check
#added_word = Word.where(:word => params[:word][:word]).first
respond_to do |format|
format.js
end
end
In the view I have the following code:
$("#added_words").append("<%= #added_word.word %>, ");
How should i change the controller in order not to render the view if no record found ( false returned)?

Not very idiomatic, but it answers your question.
def check
#added_word = Word.where(:word => params[:word][:word]).first
if #added_word.present?
respond_to {|f| f.js}
else
render :text => '' # or whatever
end
end

Related

If one record found execute show action

I wondering what would be the best practice to perform next task.
I have a search results to display from index action. Every individual record displays in the pop up through show action.
What I would love to do is to execute pop up if there is only one record found.
Here what I already tried.
def index
#companies = Company.search(params[:query]).results
#count = #companies.total
if #count == 1
return
render company_path
end
end
Seems like return, redirect_to or render aren't play well in one action.
Any other thought of doing it?
UPDATE added show action
def show
sleep 1/2
client = Elasticsearch::Client.new host:'127.0.0.1:9200', log: true
response = client.search index: 'companies', body: {query: { match: {_id: params[:id]} } }
#company = response['hits']['hits'][0]['_source']
respond_to do |format|
format.html # show.html.erb
format.js # show.js.erb
format.json { render json: #company }
end
# more code
end
The return is definitely killing you, but you're trying to render / redirect to a path for a specific resource without specifying the resource. I've taken a stab at something that might work a bit better for you:
class MyController
before_action :find_companies, only: :index
before_action :find_company, only: :show
before_action :show_company_if_matched, only: :index
def index
# do whatever you were doing here...
end
def show
respond_to do |format|
format.html # show.html.erb
format.js # show.js.erb
format.json { render json: #company }
end
# more code
end
private
def find_companies
#companies = Company.search(params[:query]).results
end
def find_company
client = Elasticsearch::Client.new host:'127.0.0.1:9200', log: true
response = client.search index: 'companies', body: {query: { match: {_id: params[:id]} } }
#company = response['hits']['hits'][0]['_source']
end
def show_company_if_matched
redirect_to company_path(#comapnies.first) if #companies.total == 1
end
end
EDIT: Updated to include show action
This is correct syntax :
def index
#companies = Company.search(params[:query]).results
#count = #companies.total
if #count == 1
render company_path # no params ?
return
else
redirect_to root_path
return
end
end
Use return after render or redirect it's good practice, because in some cases 'render' or 'redirect_to' do not do 'return' (cf: best practice ruby)
Remove the return from your controller. If I've understood your question, this should result in the behavior you're looking for:
if #count == 1
render company_path
else
# Do something else
end
If there is subsequent code in the controller that you do not want to execute, you can render and return as follows:
if #count == 1
render company_path and return
else
# Do something else
end

make variable available in all method of controller when passed in one method

Here i send the user.id as params dd
<h3><%= link_to("Lend Asset", {:controller => 'empassets', :action=> 'index', :dd => user.id})%></h3>
In controller empassets i fetch it by
def index
#id = params[:dd]
#empassets = Empasset.where(:ad => #id)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #empassets }
end
end
def show
#id = params[:dd]
#empasset = Empasset.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #empasset }
end
end
def new
#id = params[:dd]
#empasset = Empasset.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #empasset }
end
end
def edit
#id = params[:dd]
#empasset = Empasset.find(params[:id])
end
I need this #id in all new show edit method. But it takes in index only as i mention it in index. How can i make such that if Lend asset is click then #id= params[:id] have value in all methods. How can it is possible to make it available for another #id = params[:id] is not send in that controller?
Maybe will be better if you store the current user in session and after that, capture the user model with a filter in the controller, like this:
# controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_filter :set_current_user_in_model
private
def current_user
#current_user ||= User.find(params[:dd]) || User.new
end
# This method save the current user in the user model, this is useful to have access to the current user from a model and not from the controller only
def set_current_user_in_model
User.current_user current_user if not current_user.nil?
end
end
# models/user.rb
class User < ActiveRecord::Base
#...
# This is useful to get the current user inside a model
def self.current_user(user = nil)
##current_user = (user || ##current_user)
end
#...
end
Basically, my idea is store that information inside a model with a filter, you can use session if you wanth to get the information (user id).
def index
session[:user_id] = params[:dd]
#empassets = Empasset.where(:ad => session[:user_id])
respond_to do |format|
format.html # index.html.erb
format.json { render json: #empassets }
end
end
def show
#empasset = Empasset.find(session[:user_id] || params[:dd])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #empasset }
end
end
Note I used session[:user_id] || params[:dd] because maybe, the session information was not stablished and you give it :dd parameter. But if you want to stablish the #id variable, you can use a filter like before.
But I don't know what is the main problem.
Edit
# controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_filter :set_dd_param, :except => :index
def index
session[:dd] = params[:dd] # Here you write the session
#current_user ||= User.find(params[:dd]) || User.new
end
# ...
protected
def set_dd_param
params[:dd] = session[:dd] || -1 # Here you read the session a write the params variable
end
end
Sorry for the delay.
Unless you want to store it to the session, there is no way to automatically make #id available to every method in the controller.. but you can add the param to each link/form, like so:
<%= link_to("New Asset", {:controller => 'empassets', :action=> 'new', :dd => #id})%>
<%= link_to("Show Asset", {:controller => 'empassets', :action=> 'show', :dd => #id})%>
where these links are in the index view and #id is set in the index method.
Not exactly sure what the goal is here, but something like this may work.
def index
$id = params[:dd]
#empassets = Empasset.where(:ad => #id)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #empassets }
end

respond_with - How to respond with a text

I'm using the respond_to and respond_with in a rails app, but in one use case I need to respond with just a text for just one of the resource formats (:json)... But I can't find how to do this...
I want something like this (I know this doesn't work)
def create
...
respond_with(:json, render :text => "Successfully Done!")
end
Any Idea??
Thanks!
It seems that this may be what you are looking for:
def create
respond_to do |format|
format.html
format.json { render :text => "Successfully Done!" }
end
end
Andres,
The solution is this:
class TextController < ApplicationController
respond_to :json, :text
def index
respond_with do |format|
format.json {
render :text => "I'm a text provided by json format"
}
format.text {
render :text => "I'm a text"
}
end
end
end
And at your routes.rb:
match '/text' => 'text#index', defaults: { format: 'text' }

callback in controller does not works for me

I have this code in my controller:
class InvitationsController < ApplicationController
before_filter :invitations_sent!
def new
#code here
end
def create
#code here
end
private
def invitations_sent!
if current_user.invitations.size > 1
return false
format.js { render :text => "you can not send more invitations" }
else
return true
end
end
end
I call to method new with:
<%=link_to "Invite Friends", new_invitations_path, :remote =>true, :id => "invite_to_friends" %>
Why Can I access to methods new and create If I have sent 3 invitations?
I've never used remote links before so I'm not sure about that part, but you definitely need return false to come after format.js { } if you want format.js { } to actually run. Once ruby hits a return statement method execution stops.
UPDATE:
It's not totally clear from your comment what you changed. But if you want the render to happen at all that method should look like this:
def invitations_sent!
if current_user.invitations.size > 1
respond_to do |format|
format.js { render :text => "you can not send more invitations" }
end
return false
else
return true
end
end
Nevermind, the render block was not ok. It should be wrapped in a respond_to block like above.
I don't know the answer but my first step in figuring it out would be to answer these questions:
1) Is your before filter actually being called?
2) Is current_user correct, in the filter?
3) Is current_user invitations correct?
4) Does return false actually get executed?
You can look at what's going on in your filter by adding raise statements or calls to puts.
This is another way to return true/false.
respond_to do |format|
format.js { render :nothing => true, :status => 200, :content_type => 'text/json' }
end

Learning how to spec..seem to be having troubles

Here's my code I'm spec'ing:
def vote_up
get_vote
#vote.value += 1 unless #vote.value == 1
#vote.save
respond_to do |format|
format.js { render :action => "vote", :layout => false }
end
end
Seems pretty straightforward. This is what I'm trying to spec it with :
it "should vote up" do
#mock_cat = Factory.create(:category)
Category.stub(:mock_cat)
#mock_post = Factory.create(:post)
Post.stub(:current_post).and_return(#mock_post)
#vote = Factory(:vote)
get :vote_up, :id => #vote
#vote.reload.value.should == 1
end
It's returning this :
undefined method `to_i' for #<Vote:0x1052a4af8>
I can't really figure out why though. If I stubbed my mock_vote as (:vote), wouldn't it run through the controller method and get +1 attributed to it?
Update
Here's the private method from my posts_controller.rb
private
def get_vote
current_post = Post.all.detect{|r| r.id == params[:id].to_i}
#post = current_post
#vote = current_post.votes.find_by_user_id(current_user.id)
unless #vote
#vote = Vote.create(:user_id => current_user.id, :value => 0)
current_post.votes << #vote
end
end
Answer:
it "should vote up" do
#mock_cat = Factory.create(:category)
Category.stub(:mock_cat)
#post = Factory(:post)
get :vote_up, :id => #post.id
#post.reload.vote_score.should == 1
end
I recommend to move logic from controller to model. Models are much easier to spec. Instead of:
def vote_up
get_vote
#vote.value += 1 unless #vote.value == 1
#vote.save
respond_to do |format|
format.js { render :action => "vote", :layout => false }
end
end
Your controller should looks like this:
def vote_up
#vote = Vote.vote_up(params[:id])
respond_to do |format|
format.js { render :action => "vote", :layout => false }
end
end
or, if you really need get_vote (may be you should move it to before_filter?)
def vote_up
#vote.vote_up
respond_to do |format|
format.js { render :action => "vote", :layout => false }
end
end
If necessary. add exceptions (may be with rescue_from)
Then, you will need specs only in model, and some integration (rspec,steac, cucumber)
It's hard to follow what exactly your stubs are doing because you didn't post the code for get_vote. But I think you're over-using stubs when you could just be taking advantage of the factories you're already creating.
it "should vote up" do
# Does your Vote belong to a post or a category or anything? I don't know.
# Modify as needed -- Factory(:vote, :post => Factory(:post))
#vote = Factory(:vote)
get :vote_up, :id => #vote
#vote.reload.value.should == 1
end
Note the reload. Your controller's modifying a record we've already pulled from the database, so we need to reload it to check its new value.

Resources