How to make an object visible in scope of entire controller? - ruby-on-rails

So i need to get instantiate an object which requires parameters. I also need this object to be available in the scope of the entire controller once instantiated. How can this be done?
Edit: some code to help illustrate
def beginLoad(user, category)
#stuff
#gaobj = GraphAssistant.new(#arrays.fetch(0), #arrays.fetch(1))
values = #gaobj.externalize
ret = {"axis_label" => values.fetch(0), "out" => values.fetch(1), "i" => values.fetch(2)}
end
But when I try to call it again from this method:
def resumeLoad(direction)
if direction.eql? "left"
#gaobj.decrementPosition
elsif direction.eql? "right"
#gaobj.incrementPosition
end
#other stuff
end
it doesnt work. I suppose I could do all of this logic in the view, what implications will that have on performance though?

Prefix it with an #sign: #foo = Foo.new.
Update: Sounds like you need this persisted to the session.
At the end of beginLoad, add:
session[:foo] = #foo
At the beginning of resumeLoad, add:
#foo = session[:foo]

If both of those functions are being called from the same controller action, the instance variable (#gaobj) should be accessible to both. You will need to make sure that #beginLoad is called before #resumeLoad for every incoming request. Is that the problem?

Related

Set Parameter if blank

I need to set the id parameter to a value if it is wasn't submitted with the form.
Is it ok to do something like this in Rails or does this violate any standards or cause possible issues?
if params[:cart][:cart_addresses_attributes]["0"][:id].blank?
params[:cart][:cart_addresses_attributes]["0"][:id] = 1234 #default id
end
My implementation works with this logic, but I am not sure if this is the proper way to handle the issue.
There's a chance [:record_type] is nil which will lead to an undefined method error when you attempt to call [:id] on nil. Additionally, I'd find it a bit weird to directly mutate params, even though you technically can do that. I'd consider using Strong Parameter processing methods like so (added a full action, which isn't in your sample, to give more context on how this would be used):
def create
#record_type = RecordType.new(record_type_params)
if record_type.save
redirect_to #record_type
else
render :new
end
end
def record_type_params
params.require(:record_type).permit(:id).reverse_merge(id: 1234)
end
The reverse_merge call is a way to merge the user-supplied parameters into your defaults. This accomplishes what you're after in what I would consider a more conventional way and doesn't mutate params.
def cart_params
params.require(:cart).permit(:cart_addresses_attributes => [:id]).tap do |p|
p[:cart_addresses_attributes]["0"][:id] ||= 1234
end
end
if params[:record_type][:id].nil? # or replace ".nil?" with "== nil"
params[:record_type][:id] = 1234
end
personally, this is the way I prefer to do it. Some ways are more efficient than others, but if that works for you I'd roll with it.

Ruby/Rails. Passing variable into parameters

I have a lot pages in my app. And for every page I need to create a new variable and describe method. And if I will need to change something, I will have to change on every page. So the idea is to create universal method in application_controller.rb.
For example, I have a lot of categories in my Posts and to target some category for page I did: #posts_for_interesting = Post.where(interesting: true), other category, for example: #posts_for_photos = Post.where(photos: true).
And the application_controller.rb, have to look something like that:
def posts_for_all_pages(category)
#posts = Posts.where(category: true)
end
And, for example, photos_controller.rb must look like that:
posts_for_all_pages(photos)
And how can I pass this photos to Post.where(category: true)?
Right here in your original code:
def posts_for_all_pages(category)
#posts = Posts.where(category: true)
end
The category in Posts.where(category: true) will not a variable, it will be a hard coded symbol :category, so it won't work. Instead, write this:
def posts_for_all_pages(category)
#posts = Posts.where(category => true)
end
a small change, but definitely has a different meaning.
Then when you call the method, you pass a symbol to it:
posts_for_all_pages(:photos)

Create a method that changes attribute (integer) rails

I have an integer in my Parent Object's table called completion_status with a default value of 0. Id like to set this to the same value as "#parent.child.count('completion', :distinct => true)", but I have no idea how to do this in the controller, or even if the controller is the best place to do this.
I know there's not much information included here, but let me know if I'm missing something important. I'm having kind of a brain-fart moment here.
EDIT: Just tried:
def set_completion
#app = App.find(params[:id])
#app.update_attribute(:completion_status => #app.elements.count('completion', :distinct => true))
end
From what I understand, this value could possibly change everytime you create a new child, because creating a new child will change the value of #parent.child.count, so you want to reset completion_status everytime you create or update a new child, so one way to do this is inside the create and update action of the ChildrenController -assuming you have one :
def create
#parent = Parent.find(params[:parent_id]
#child = #parent.children.build(child_params)
if #child.save
#parent.completion_status = #parent.children.count // this is the line to add
end
end
This code could be improved in different ways but I'm just giving you an example.

Change scope based on parameters

How would I change a scope on a chain dynamically based on a parameter in the URI?
For example:
http://www.example.com/object?status=approved
would lead to the ObjectController#index:
def index
#objects = Object.approved.<other-chains>
end
If status was pending, the controller method would be something like:
#objects = Object.pending.<other-chains>
You wouldn't. You'd define two scopes, pending and approved, and invoke them conditionally based on the URL. You can't (or at the very least, shouldn't) change your scopes dynamically at run time, or you're going to break subsequent requests terribly.
If you want to avoid branching if/elses, you can just send the method to your model, after making sure that it is in a pre-approved list of acceptable methods:
class MyController
def index
#objects = Object.send(scope).chain.chain.chain
end
protected
# return "pending", "approved", or "scoped",
# so that Object.send(scope) *always* works, and returns a chainable relation
def scope
scopes = %w(pending approved)
scopes.include?(params[:status].to_s) ? params[:status] : "scoped"
end
end
By defaulting to "scoped", you ensure that the method invoked will return a relation onto which additional methods can be chained.
How about:
#objects = Object.send(params[:status])

How can I pass objects from one controller to another in rails?

I have been trying to get my head around render_to but I haven't had much success.
Essentially I have controller methods:
def first
#I want to get the value of VAR1 here
end
def second
VAR1 = ["Hello", "Goodbye"]
render_to ??
end
What I can't figure out is how to accomplish that. Originally I just wanted to render the first.html.erb file but that didn't seem to work either.
Thanks
Edit: I appreciate the answers I have received, however all of them tend to avoid using the render method or redirect_to. Is it basically the case then that a you cannot pass variables from controller to controller? I have to think that there is some way but I can't seem to find it.
It is not a good idea to assign the object to a constant. True this is in a global space, but it is global for everyone so any other user going to this request will get this object. There are a few solutions to this.
I am assuming you have a multi-step form you are going through. In that case you can pass the set attributes as hidden fields.
<%= f.hidden_field :name %>
If there are a lot of fields this can be tedious so you may want to loop through the params[...] hash or column_names method to determine which attributes to pass.
Alternatively you can store attributes in the session.
def first
#item = Item.new(params[:item])
session[:item_attributes] = #item.attributes
end
def second
#item = Item.new(session[:item_attributes])
#item.attributes = params[:item]
end
Thirdly, as Paul Keeble mentioned you can save the model to the database but mark it as incomplete. You may want to use a state machine for this.
Finally, you may want to take a look at the Acts As Wizard plugin.
I usually don't have my controllers calling each other's actions. If you have an identifier that starts with a capital letter, in Ruby that is a constant. If you want to an instance level variable, have it start with #.
#var1 = ["Hello", "Goodbye"]
Can you explain what your goal is?
Have you considered using the flash hash? A lot of people use it solely for error messages and the like, it's explicitly for the sort of transient data passing you might be interested in.
Basically, the flash method returns a hash. Any value you assign to a key in the hash will be available to the next action, but then it's gone. So:
def first
flash[:var] = ["hello", "goodbye"]
redirect_to :action => :second
end
def second
#hello = flash[:var].first
end
way 1
Global variable
(fail during concurrent requests)
way 2
class variable
(fail during concurrent requests)
way 3
Stash the object on the server between requests. The typical way is to save it in the session, since it automatically serializes/deserializes the object for you.
Serialize the object and include it in the form somewhere, and
deserialize it from the parameters in the next request. so you can store attributes in the session.
def first
#item = Item.new(params[:item])
session[:item_attributes] = #item.attributes
end
def second
#item = Item.new(session[:item_attributes])
#item.attributes = params[:item]
end
way 4
The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed to the very next action and then cleared out.
def new
#test_suite_run = TestSuiteRun.new
#tests = Test.find(:all, :conditions => { :test_suite_id => params[:number] })
flash[:someval] = params[:number]
end
def create
#test_suite_run = TestSuiteRun.new(params[:test_suite_run])
#tests = Test.find(:all, :conditions => { :test_suite_id => flash[:someval] })
end
way 5
you can use rails cache.
Rails.cache.write("list",[1,2,3])
Rails.cache.read("list")
But what happens when different sessions have different values?
Unless you ensure the uniqueness of the list name across the session this solution will fail during concurrent requests
way 6
In one action store the value in db table based on the session id and other action can retrieve it from db based on session id.
way 7
class BarsController < UsersController
before_filter :init_foo_list
def method1
render :method2
end
def method2
#foo_list.each do | item|
# do something
end
end
def init_foo_list
#foo_list ||= ['Money', 'Animals', 'Ummagumma']
end
end
way 8
From action sent to view and again from view sent to other actions in controller.

Resources