callback in controller does not works for me - ruby-on-rails

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

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

Rails 4: what is wrong with this method?

I'm upgrading an application to Rails 4 and I cannot for the life of me figure out what is wrong with this method. The offender's the update method:
def update
respond_to do |format|
if #doc.articles.find_index { |a| a.changed? }
#doc.publications.destroy_all
end
if #doc.update_attributes(params[:doc])
#doc.create_activity :update, owner: current_user
if current_user.brand.editable? && params[:editing]
format.html { redirect_to editing_url(#doc) }
else
format.html { redirect_to share_url(#doc.user.ftp, #doc) }
end
end
end
end
Clicking submit generates this error:
ActionController::UnknownFormat in DocsController#update
and highlights this line:
respond_to do |format|
The create method works fine, it looks like this:
def create
#doc = Doc.new(params[:doc])
respond_to do |format|
if #doc.save
#doc.create_activity :create, owner: current_user
if current_user.brand.editable? && params[:editing]
format.html { redirect_to doc_editing_url(#doc) }
else
format.html { redirect_to share_url(#doc.user.ftp, #doc) }
end
else
format.html { render action: "new" }
end
end
end
Any thoughts at all? I'm totally stuck.
Oh, I've got this private method as a before_action too, so it's not that:
private
def set_document
#doc = Doc.find(params[:id])
end
EDIT
I found this quasi-explanation:
In Rails 4.0, ActionController::UnknownFormat is raised when the
action doesn't handle the request format. By default, the exception is
handled by responding with 406 Not Acceptable, but you can override
that now. In Rails 3, 406 Not Acceptable was always returned. No
overrides.
which makes me think it's something to do with routes, but my routes should be default if I've declared them like so, yes?
resources :docs, :except => [:new, :show] do
get "adjust/:state" => "docs#adjust", :as => :adjust
patch "editing" => "docs#editing", :as => :editing
patch "reupdate/" => "docs#reupdate", :as => :reupdate
get "pdf" => "docs#pdf", :as => :pdf
collection { post :sort }
end
EDIT 2
Adding the JSON to the controller, i.e.:
format.html { redirect_to share_url(#doc.user.ftp, #doc) }
format.json { render action: 'share', status: :created, location: #doc }
gives me a no method error and seems to redirect me back to the edit page:
Showing .../fin/app/views/docs/_form.html.erb where line #19 raised:
undefined method `covers?' for nil:NilClass
Really no idea what's going on here.
One possible reason can be that if #doc.update_attributes(params[:doc]) returns false there is no format block being executed in the update method.
Usually you are rendering the edit action in that case.
If you are only serving HTML then you don't need respond_to and format.html at all.

Rails3: not render view if no record found

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

Rails 3: How to "redirect_to" in Ajax call?

The following attempt_login method is called using Ajax after a login form is submitted.
class AccessController < ApplicationController
[...]
def attempt_login
authorized_user = User.authenticate(params[:username], params[:password])
if authorized_user
session[:user_id] = authorized_user.id
session[:username] = authorized_user.username
flash[:notice] = "Hello #{authorized_user.name}."
redirect_to(:controller => 'jobs', :action => 'index')
else
[...]
end
end
end
The problem is that redirect_to doesn't work.
How would you solve this ?
Finally, I just replaced
redirect_to(:controller => 'jobs', :action => 'index')
with this:
render :js => "window.location = '/jobs/index'"
and it works fine!
There is very easy way to keep the flash for the next request. In your controller do something like
flash[:notice] = 'Your work was awesome! A unicorn is born!'
flash.keep(:notice)
render js: "window.location = '#{root_path}'"
The flash.keep will make sure the flash is kept for the next request.
So when the root_path is rendered, it will show the given flash message. Rails is awesome :)
I think this is slightly nicer:
render js: "window.location.pathname='#{jobs_path}'"
In one of my apps, i use JSON to carry on the redirect and flash message data. It would look something like this:
class AccessController < ApplicationController
...
def attempt_login
...
if authorized_user
if request.xhr?
render :json => {
:location => url_for(:controller => 'jobs', :action => 'index'),
:flash => {:notice => "Hello #{authorized_user.name}."}
}
else
redirect_to(:controller => 'jobs', :action => 'index')
end
else
# Render login screen with 422 error code
render :login, :status => :unprocessable_entity
end
end
end
And simple jQuery example would be:
$.ajax({
...
type: 'json',
success: functon(data) {
data = $.parseJSON(data);
if (data.location) {
window.location.href = data.location;
}
if (data.flash && data.flash.notice) {
// Maybe display flash message, etc.
}
},
error: function() {
// If login fails, sending 422 error code sends you here.
}
})
Combining the best of all answers:
...
if request.xhr?
flash[:notice] = "Hello #{authorized_user.name}."
flash.keep(:notice) # Keep flash notice around for the redirect.
render :js => "window.location = #{jobs_path.to_json}"
else
...
def redirect_to(options = {}, response_status = {})
super(options, response_status)
if request.xhr?
# empty to prevent render duplication exception
self.status = nil
self.response_body = nil
path = location
self.location = nil
render :js => "window.location = #{path.to_json}"
end
end
I didn't want to modify my controller actions so I came up with this hack:
class ApplicationController < ActionController::Base
def redirect_to options = {}, response_status = {}
super
if request.xhr?
self.status = 200
self.response_body = "<html><body><script>window.location.replace('#{location}')</script></body></html>"
end
end
end

How do I update all other records when one is marked as default?

I am trying to change all of the default_standing fields to FALSE for all other records when someone marks one as TRUE. That way I will only ever have one default record in the table. Here is what I am doing in both create and update in my controller, but it doesn't seem to be working:
def update
#standing = Standing.find(params[:id])
if #standing.default_standing
#standings = Standing.where(["default_standing = ? AND id != ?", true, params[:id]])
#standings.each do |s|
s.default_standing = false
s.save!
end
end
respond_to do |format|
if #standing.update_attributes(params[:standing])
format.html { redirect_to(#standing, :notice => 'Standing was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #standing.errors, :status => :unprocessable_entity }
end
end
end
I think the condition is wrong in shingara's update_all.
Should update all where id is not standing.id:
class Standing
def self.all_false_instead_of(standing)
return if standing.default_standing
Standing.update_all(["default_standing = ?", false], ['id <> ?', standing.id])
standing.update_attributes!(:default_standing, true)
end
end
class Standing
def self.all_false_instead_of(standing)
return if standing.default_standing
Standing.update_all("default_standing = false", {:id => standing.id})
standing.update_attributes!(:default_standing, true)
end
end
It's better in Model and something like that I suppose. Have you the unit test failing ?
In your controller
def update
#standing = Standing.find(params[:id])
Standing.all_false_instead_of(#standing)
end
In your code you never push default_standing to true in you #standing

Resources