How do I pass an array to another action in a controller? - ruby-on-rails

I created a array in start for displaying the IDs one by one, and I want to the same array used in another action called next. In start I created a array called ques. I want to use ques in next.
START:
class AnswersController < ApplicationController
def start
#user = current_user
#student = Student.find_by_admission_no(#user.username)
#exam_group = ExamGroup.find_by_id(params[:exam_group_id])
#answer = Answer.new(params[:ans])
#module = params[:student_additional_field]
#questions = shuf_order(#exam_group,#module)
ques = []
#questions.each do |a|
ques.push q.id unless q.id.nil?
end
a = ques.first
#s = 1
#ans = Question.find_by_id(a)
render(:update) do |page|
page.replace_html 'main', :partial => 'ans', :object => #ans
page.replace_html 'quespan', :partial => 'ques'
end
end
Next:
def next
#user = current_user
#student = Student.find_by_admission_no(#user.username)
#exam_group = ExamGroup.find_by_id(params[:exam_group_id])
#answer = Answer.new(params[:ans])
#answer.answer = params[:answer]
#answer.exam_group_id = #exam_group.id
#answer.user_id = #user.id
passed_question = params[:passed_question]
#answer.questions_id = passed_question
#question = Question.find_by_id(passed_question)
#module = Question.find_by_sql ["SELECT student_additional_field_id FROM questions WHERE id=#{passed_question}"]
student_additional_field_id = #module[0].student_additional_field_id
#questions = shuf_order(#exam_group,student_additional_field_id)
a = #questions.first
#answer.modules_id = student_additional_field_id
if #answer.save
#ans = Question.find_by_id(a, :conditions => [' id not in (?)',answered])
unless #ans.nil?
render(:update) do |page|
page.replace_html 'main', :partial => 'ans', :object => #ans
end
else
render(:update) do |page|
page.replace_html 'main', :partial => 'ans2'
end
end
end
end

The usual way to pass variables between actions is the flash variable.
In start:
flash[:ques] = []
flash[:ques].push 'whatever'
In next:
flash[:ques]
to access the saved var.
But in your case maybe you want to save your ques in session or DB to use ques in more than these 2 actions:
In start:
session[:ques] = []
session[:ques].push 'whatever'
In next:
session[:ques]
Or in DB, you maybe would need a new table.

Related

Ruby on rails method partials?

I was wondering if it is possible to create a method partial in ruby on rails, for example I have this code;-
#cart = Cart.where(:user_id => current_user.id).first if user_signed_in?
#slots = #cart.slots.first
#slot_list = [#slots.slot_one, #slots.slot_two, #slots.slot_three, #slots.slot_four, #slots.slot_five,
#slots.slot_six, #slots.slot_seven, #slots.slot_eight, #slots.slot_nine, #slots.slot_ten]
#user_products = []
#product = []
#slot_list.each do |item|
if item.nil?
p 'Item empty'
else
#product << item
end
end
#product.each do |item|
items = Product.where(:product_id => item).first
#user_products << items
end
Written in multiple methods to get the #user_products, I was wondering if there was a way so I don't have to write this all the time and possibly run a method or use a partial?
Would it be worth creating a helper that does this and returns the #user_products variable?
I took my own advice and created two helpers, one to return the #user_products and another to return the #total.
I added the names of the methods to our helper_method
helper_method :user_is_admin?, :authenticate_admin!, :product_available?, :get_user_products!, :get_user_total!
then added these two methods at the bottom of the file;-
get_user_products!
def get_user_products!
#cart = Cart.where(:user_id => current_user.id).first if user_signed_in?
#slots = #cart.slots.first
#slot_list = [#slots.slot_one, #slots.slot_two, #slots.slot_three, #slots.slot_four, #slots.slot_five,
#slots.slot_six, #slots.slot_seven, #slots.slot_eight, #slots.slot_nine, #slots.slot_ten]
#user_products = []
#product = []
#slot_list.each do |item|
if item.nil?
p 'Item empty'
else
#product << item
end
end
#product.each do |item|
items = Product.where(:product_id => item).first
#user_products << items
end
return #user_products
end
get_user_total!
def get_user_total!
#total = 0
#cart = Cart.where(:user_id => current_user.id).first if user_signed_in?
#slots = #cart.slots.first
#slot_list = [#slots.slot_one, #slots.slot_two, #slots.slot_three, #slots.slot_four, #slots.slot_five,
#slots.slot_six, #slots.slot_seven, #slots.slot_eight, #slots.slot_nine, #slots.slot_ten]
#user_products = []
#product = []
#slot_list.each do |item|
if item.nil?
p 'Item empty'
else
#product << item
end
end
#product.each do |item|
items = Product.where(:product_id => item).first
#user_products << items
end
#user_products.each do |p|
#total += p.product_price
end
return #total
end
To use these methods inside whatever controller you then do the following;-
#user_products = get_user_products!
#total = get_user_total!
I assume this is in a controller?
What you want is to use plain old Ruby objects (POROs). So, you might have something like this:
class UserProducts
class << self
def get(options={})
#cart = Cart.where(:user_id => current_user.id).first if user_signed_in?
#slots = #cart.slots.first
#slot_list = [
#slots.slot_one,
#slots.slot_two,
#slots.slot_three,
#slots.slot_four,
#slots.slot_five,
#slots.slot_six,
#slots.slot_seven,
#slots.slot_eight,
#slots.slot_nine,
#slots.slot_ten
]
#user_products = []
#product = []
#slot_list.each do |item|
if item.nil?
p 'Item empty'
else
#product << item
end
end
#product.each do |item|
items = Product.where(:product_id => item).first
#user_products << items
end
end
end
Then, in your controller, you'd do something like:
class FooController < ApplicationController
def index
UserProducts.get(user_id: current_user.id)
end
end
So, UserProducts is essentially a service object. I think some people call them use cases. I tend to call them 'managers'. I put them in their own directory as app/managers/user_products.rb.

Ruby on Rails filter array using three fields

I am trying to search through my model using 3 columns. Also if the column is empty, it is valid. This is how I am doing it
def getactivityfortoday
#temp = params[:temp]
logger.debug "params temp:#{#temp.inspect}"
#sky = params[:sky]
#day = params[:day]
#todaysactivities = []
#activities=[]
#finaldata = []
#activities = Weatherclockactivity.all
#attemptactivities = []
#attemptactivities = #user.attempts
for activity in #activities do
logger.debug "activity: #{activity.attributes.inspect}"
if #temp.to_i < activity.temperatureMax.to_i && #temp.to_i > activity.temperatuureMin.to_i
if #sky == activity.sky || activity.sky == ""
if #day == activity.day
#todaysactivities << activity
end
end
end
end
for activity in #todaysactivities
for attempt in #attemptactivities
if attempt == activity
finaldata << {activity: activity, attempt: "yes"}
else
finaldata << {activity: activity, attempt: "no"}
end
end
end
respond_to do |format|
format.html { render action: "new" }
format.json { render json: #finaldata }
end
The response I get is an empty array but I should be getting 3 rows as a response.
spelling mistake here
activity.temperatuureMin.to_i
And
finaldata << {activity: activity, attempt: "yes"}
should be
#finaldata << {activity: activity, attempt: "yes"}
Also you could be more concise
def getactivityfortoday
#temp = params[:temp]
logger.debug "params temp:#{#temp.inspect}"
#sky = params[:sky]
#day = params[:day]
#activities = Weatherclockactivity.all
#attemptactivities = #user.attempts
#finaldata = #activities.map do |activity|
if (activity.temperatureMin.to_i + 1...activity.temperatureMax.to_i).include?(#temp.to_i) && ( #sky == activity.sky || activity.sky == "") && #day
#attemptactivities.include?(activity) ? {activity: activity, attempt: "yes"} : {activity: activity, attempt: "no"}
end
end.compact
respond_to do |format|
format.html { render action: "new" }
format.json { render json: #finaldata }
end
end
How about something like this?
I tried to make it a balance of readability and conciseness. First we filter for the desired activities. Then we structure the output. This should be easier to debug.
def getactivityfortoday
#temp = params[:temp].to_i
#sky = params[:sky]
#day = params[:day]
#activities = Weatherclockactivity.all
#attemptactivities = #user.attempts
selected_activities = #activities.select do |activity|
# Make sure it's the right temperaure
return false unless (activity.temperatureMin.to_i + 1 ... activity.temperatureMax.to_i).include? #temp
# Make sure the sky matches, or the sky is blank
return false unless (#sky.blank? || #sky.activity == activity.sky)
# Make sure the day matches
return false unless #day == activity.day
# Otherwise, it's good!
return true
end
selected_attempted_activities = selected_activities.map do|activity|
ret = {activity: activity}
ret[:attempt] = #attemptactivities.include?(activity) ? "yes" : "no"
ret
end
respond_to do |format|
format.html { render action: "new" }
format.json { render json: selected_attempted_activities }
end
end
There are a few typos in your original (for instance, #finaldata not finaldata). Make sure that you spell instance variables (things starting with #, like #sky) correctly, since if you try to access an undefined instance variable, it'll silently default to nil.
The best and flexible way is to use ActiveModel::Model
It allows you to use many more useful methods.
it will seems like:
app/models/activity_report.rb
Class ActivityReport
include ActiveModel::Model
attr_accessor :day, :activity # and etc.
validates :day, presence: true
def day
#day.to_s # for example
end
def day=(value)
#day = value - 1.month # for example every date which user set will set on one month ago
end
# and etc
end
app/controllers/posts_controller.rb
...
def index
#activity = ActivityReport.new(params[:activity])
end
def create
#activity.create!
end
...
app/views/posts/index.html.haml
= form_for #activity do |f|
= f.day
For more information you could take a look at:
http://edgeapi.rubyonrails.org/classes/ActiveModel/Model.html
http://railscasts.com/episodes/219-active-model (old)
http://railscasts.com/episodes/416-form-objects (newer, but a little complex)

Why am I getting undefined method 'save' error?

My code is this
def footstamp
if current_user
#user = User.find(params[:id])
#tracking = Tracking.where(:user_id => current_user.id, :target_user_id => #user.id)
if #tracking
#tracking.accessed_at = Time.now
#tracking.save
else
#tracking = Tracking.new
#tracking.user_id = current_user.id
#tracking.target_user_id = #user.id
#tracking.accessed_at = Time.now
#tracking.save
end
end
end
Then I get this error
NoMethodError (undefined method `save' for []:ActiveRecord::Relation):
Use:
#tracking = Tracking.where(:user_id => current_user.id, :target_user_id => #user.id).first
You are getting this error because the result of your method do not return a Tracking, but an array of Trackings.
Either you introduce more conditions to match only one Tracking, or use the first method or iterate over the results,
To use first:
#tracking = Tracking.where(:user_id => current_user.id, :target_user_id => #user.id).first
Iterate:
Tracking.where(:user_id => current_user.id, :target_user_id => #user.id).each do |tracking|
if tracking
tracking.accessed_at = Time.now
tracking.save
else
tracking = Tracking.new
tracking.user_id = current_user.id
tracking.target_user_id = #user.id
tracking.accessed_at = Time.now
tracking.save
end
end
Optimised answer,
def footstamp
if current_user
#user = User.find(params[:id])
#tracking = Tracking.where(:user_id => current_user.id, :target_user_id => #user.id).first_or_create
#tracking.accessed_at = Time.now
#tracking.save
end
end
More usefull methods here

Eval alternative

I have a bazillion controllers in my app, and I was wondering about using some metaprogramming to make maintenance less of a headache. This works, but it's spiked with danger in the form of eval:
def plural_action(method_name)
class_name = self.class.to_s.gsub( %r{^(\w*)Controller} ) {|s| $1 }
#title = "#{method_name.to_s.titlecase} of #{class_name}"
eval "#q = #{class_name.singularize}.where(:client_id => current_user.client_id).search(params[:q])"
eval "##{class_name.downcase} = #q.result(:distinct => true).paginate(:page => params[:page])"
eval "session[:query] = ##{class_name.downcase}.map(&:id)"
eval "respond_with(##{class_name.downcase})"
end
Can I do this without using eval? I've tinkered with instance_variable_set, send and const_get but no luck so far.
Here's an example of what I'd like the method to eval to.
def index
#title = "Index of Books"
#q = Book.where(:client_id => current_user.client_id).search(params[:q])
#books = #q.result(:distinct => true).paginate(:page => params[:page])
session[:query] = #books.map(&:id)
respond_with(#books)
end
There's a magnificent method constantize which turns a string into the constant (of which class types are an example) it represents. With that in mind, I think you could rewrite your method as:
def plural_action(method_name)
class_name = self.class.to_s.gsub( %r{^(\w*)Controller} ) {|s| $1 }
#title = "#{method_name.to_s.titlecase} of #{class_name}"
#q = class_name.singularize.constantize.where(:client_id => current_user.client_id).search(params[:q])
self.instance_variable_set("##{class_name.downcase}", #q.result(:distinct => true).paginate(:page => params[:page]))
session[:query] = self.instance_variable_get("##{class_name.downcase}").map(&:id)
respond_with(self.instance_variable_get("##{class_name.downcase}"))
end
def plural_action(method_name)
class_name = self.class.to_s.gsub( %r{^(\w*)Controller} ) {|s| $1 }
#title = "#{method_name.to_s.titlecase} of #{class_name}"
#q = class_name.singularize.constantize.where(:client_id => current_user.client_id).search(params[:q])
instance_variable_set class_name.downcase, #q.result(:distinct => true).paginate(:page => params[:page])
session[:query] = #q_result.map(&:id)
respond_with(#q_result)
end

Rails validations. Needs data from other stuff. Multiple forms. Not being DRY

(Rails newbie)
Hello!
I am feeling like I am reusing a lot of my code and I feel there has to be a better way to do this... (I am sure there is...)
What I have is a Settings page, where you can create categories and procedures (which belong to a category).
index Settings action:
def categories_and_procedures
#prefs = #current_practice.preferences
#category = #current_practice.categories.build
#categories = #current_practice.categories.all
#procedure = #current_practice.procedures.build
end
In the view is a list with all the current categories and a form to create a new one. In the Category model is a validation (validates_uniqueness_of :name).
The create action:
def create_category
#category = #current_practice.categories.build(params[:category])
if #category.save
flash[:notice] = "New category created: <i>#{#category.name}</i>"
redirect_to :action => "categories_and_procedures"
else
##Duplicate code!!!!!!
#prefs = #current_practice.preferences
#category = #current_practice.categories.build
#categories = #current_practice.categories.all
#procedure = #current_practice.procedures.build
##Duplicate code!!!!!!
render :action => "categories_and_procedures"
end
end
Is there a way I can move it to a function I can call? Helper? Filters?
I don't know.
Thank you!
Just write:
def create_category
#category = #current_practice.categories.build(params[:category])
if #category.save
flash[:notice] = "New category created: <i>#{#category.name}</i>"
redirect_to :action => "categories_and_procedures"
else
categories_and_procedures
render :action => "categories_and_procedures"
end
end
It will look better if you will add some setup method:
def setup_object
#prefs = #current_practice.preferences
#category = #current_practice.categories.build
#categories = #current_practice.categories.all
#procedure = #current_practice.procedures.build
end
and call it from categories_and_procedures and from create_category.

Resources