How to invoke a method in controller? - ruby-on-rails

I had the following code in my create action.
tasks_comtroller.rb
def create
#task = current_user.tasks.build(task_params)
#task.complete = false
n=1
loop do
unless Task.find_by priority: n
#task.priority=n
break
end
n+=1
end
respond_to do |format|
if #task.save
format.html { redirect_to user_tasks_path(current_user) }
format.js
else
format.html { render action: 'new' }
format.js
end
end
end
Then I took out some part I made a method inside my task model.
class Task < ActiveRecord::Base
def priority_increment
n=1
loop do
unless Task.find_by priority: n
#task.priority=n
break
end
n+=1
end
end
end
How can I now correctly invoke this method from controller?

Thats really inefficient since each iteration has to do a database query - instead do Task.order(:priority).first and let the database do the work.
class Task < ActiveRecord::Base
def self.heighest_priority
# .try lets us handle the case where there
# are no Tasks gracefully
p = Task.order(:priority).first.try(:priority)
# return the highest + 1 or 1 if there are no tasks.
p ? p + 1 : 1
end
end
Calling methods in ruby in exactly the same no matter where you are calling the function:
obj.some_method # in Ruby the parens are optional
obj.some_method(someArg)
obj.some_method(someArg) do
# blocks are awesome.
end
Here we have a class method - we call it by Task.heighest_priority.
So lets refactor the create method to use our new method:
def create
#task = current_user.tasks.build(task_params) do |t|
t.priority = Task.heighest_priority
t.complete = false
end
if #task.save
format.html { redirect_to user_tasks_path(current_user) }
format.js
else
format.html { render action: 'new' }
format.js
end
end

If you want to put that part of code into the model, you have to call self instead of the instance variable #task like so:
class Task < ActiveRecord::Base
def priority_increment
n=1
loop do
unless Task.find_by priority: n
self.priority=n
break
end
n+=1
end
end
end
Afterwards you can call it on the task instance:
#task.priority_increment

Related

how to stop execution after redirect_to is called

i wrote an action which is again invoking another private method,
if a specific condition is met i want to redirect to some other page or else continue the execution.
but i was unable to do,
when i tried to use redirect_to root_path it says double render,
it is actually trying to execute the action statements which was actually called instead of rendering from the private method.
def actual_method_called
data1 = params[:data1]
method_2(data1)
data2 = params[:data1]
method_2(data2)
render json: {status: 'ok' }
end
private
def method_2(data)
if data.valid?
puts 'continue the execution'
else
redirect_to root_path and return
end
end
You can return a value from the called method...
def method_2(data)
if data.valid?
puts 'continue the execution'
return
else
redirect_to root_path
return :redirected
end
end
Wen you call it you store the returned value
def actual_method_called
data1 = params[:data1]
return_status ||= method_2(data1)
data2 = params[:data1]
return_status ||= method_2(data2)
render json: {status: 'ok' } unless return_status == :redirected
end

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 3 after_destroy observer not being called

Here is my model...
app/controllers/registrations_controller.rb
def destroy
#registration = Registration.find(params[:id])
#registration.cancelled = true
#registration.save
respond_to do |format|
format.html { redirect_to root_url, notice: 'Registration was successfully canceled.' }
format.json { head :no_content }
NsoMailer.after_cancellation_email(#registration).deliver
end
end
app/models/registration_observer.rb
class RegistrationObserver < ActiveRecord::Observer
#close registration after seats are filled
def after_create(registration)
if registration.orientation != nil
#orientation = registration.orientation
close_orientation if seats_equal_zero
end
end
#opens registration if a registration is removed
def after_destroy(registration)
if registration.orientation != nil
#orientation = registration.orientation
open_orientation if seats_equal_zero == false
end
end
...the after_create action is working fine, but after_destroy is not. This is just name based correct? Naming the action in the observer 'after_destroy' links it the the corresponding controller action 'destroy' no?
I also added puts statements in both the controller and observer actions. I am making it to the controller action OK, but not the observer.
It doesn't link it to controller action destroy. It links it to the model.
In order for after_destroy to execute, you should do
#registration.destroy
You can have an after_save callback and have the same effect
def after_save(registration)
return unless registration.cancelled
if registration.orientation != nil
#orientation = registration.orientation
open_orientation if seats_equal_zero == false
end
end
You can have a look at the documentation for more information

simple query on scaffolding rails

So my simple question is, i want to call a mailer if particular column is updated in database with the form based on below controller. But i dont know how to take the column name ... I am doing like if #style.category after if #style.save but not working.
Controller
def new
#style = Style.new
#users = User.where('username <> ?', current_user.username)
respond_to do |format|
format.html # new.html.erb
format.json { render json: #style }
end
end
def create
#style = Style.new(params[:style])
#style.sender = current_user
respond_to do |format|
if #style.save,
### want to call mailer here , based on if column "category" is updated or not
if #style.receiver
format.html { redirect_to user_path(#style.receiver.username), notice: "successs!"}
else
format.html { redirect_to root_path, notice: 'Success!' }
end
add a after_save callback inside the model can help
class Style < ActiveRecord::Base
after_save :send_email
def send_email
if changed_attributes.has_key?('category')
call the mailer here
end
end
end

ActiveRecord::RecordNotSaved - Forcing nested redirect

Morning All,
After spending most of the night figuring out how to put a limit on my model creation I finally got somewhere. The nested statement is now presenting me with not saved which is great news.
However I cannot seem to get the redirect or flash[:base] to work. Here is the code below:
class SnippetsController < ApplicationController
before_filter :find_book
def create
if #snippet = #book.snippets.create!(params[:snippet])
redirect_to #book
else
flash[:base]
#render
end
end
def approve
##snippet = #book.snippet.find(params[:id])
if #snippet.update_attribute(:approved, true)
redirect_to users_path
else
render root_path
end
end
def edit
#snippet = #book.snippets.find(params[:id])
end
def update
#snippet = #book.snippets.find(params[:id])
respond_to do |format|
if #snippet.update_attributes(params[:snippet])
format.html { redirect_to #book, notice: 'Comment was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
private
def find_book
#book = Book.find(params[:book_id])
end
end
Models parent (book)
class Book < ActiveRecord::Base
has_many :snippets
attr_accessible :title, :book_id, :size
def snippets_limit_reached?
if size == 0
self.snippets.count >= 2
elsif size == 1
self.snippets.count >= 3
elsif size == 2
self.snippets.count >= 4
else
return false
end
end
end
Child (Snippet)
class Snippet < ActiveRecord::Base
before_create :check_limit
belongs_to :book
attr_accessible :content, :book_id
validates :book_id, presence: true
def check_limit
if book.snippets_limit_reached?
errors.add :base, 'Snippet limit reached.'
return false
end
return true
end
end
Let me know if you need anything else, just fyi when it's running I cannot get past the nested create!
if #snippet = #book.snippets.create!(params[:snippet])
Bang methods (create!, save!) throw errors when unsuccessful, instead of returning, what evaluates to false.
Removing the bang should fix this problem.

Resources