Ruby on rails, pass an argument from one action to another - ruby-on-rails

I have two actions in my controller:search, show_db.
say, they look like this:
def search
#uploads=current_user.uploads
end
def show_db
end
I need to pass arguments (#uploads) from search-action to show_db-action. (I know I could write #uploads=current_user.uploads in show_db, but I cannot, it is much more complex.)
smt like this:
def search
#uploads=current_user.uploads
show_db(#uploads)
end
def show_db(list)
blablabla
end
Is it possible to do?=)
Many thanks in advance.

If you want to pass the result of one method to another it's pretty simple in Ruby, your second code block should work, you just need to use the list variable from the parameter in your method
def show_db(list)
x = list
list.do_somethings
etc
end

Create a third method that knows how to create #uploads, use it from both actions.
Also, if in your index action you want to render show_db with #uploads variable, you can do this:
def search
#uploads=current_user.uploads
if something
return show_db(#uploads)
end
end
def show_db(list)
blah
render 'show_db'
end
But in this case, show_db is just a method, not a controller action.

You probably want to use a variable across actions. You should know that each time you make a request from browser, you are creating a new instance of controller. Hence, your variables would not work as they should because you will actually be trying to access an instance variable across instances. An impossible task.
I suggest using sessions to store information across multiple requests.
Google up how to use sessions.

Related

How does rails choose which version of an instance variable to render?

I'm fairly new to rails & I'm trying to understand why rails chooses one version of an instance variable over another.
In the controller I have my instance variables defined.
def show
#discussions = Discussion.all.order('created_at desc')
end
def new
#discussion = current_user.discussions.build
end
If I were to call #discussion in one of my views, which version of the variable would it choose?
Each action in the controller (show and new) correspond to and render views with the same name. So, your show method in the controller renders app/views/controller_name/show.html.erb, unless you tell it otherwise by calling render explicitly.
The only instance variables available to show.html.erb are the ones defined in the show action of the controller. The same goes for other actions.
I'm also new to rails, but let me take a crack. I think in both cases, #discussion will be the same thing, the one which it is assigned to. So in your code snippet, if you make a GET call to /controller_route/new it will show you exactly what you intended - current_user.discussions.build.
If you make a GET call to /controller_route, it will be nil, since you haven't defined it. #discussions has no bearing on the evaluation.
But again this is my guess; Would be glad to be educated/corrected on this.

Package instance variables in rails controllers?

I'm overwhelmed by managing instance variables in controllers so am thinking if there's a better way to manage them.
My situation is, I'm having a PagesController that handles the front page rendering. In the front page, I have multiple small forms that originally belong to different controllers (For example, make a new post form, and there's a PostsController dedicated for it but for convenience you can make an easy post just at the front page.) and they all need their corresponding instance variable to hold the form (e.g. new post form needs a #post object).
It turns out to me, that I have to manually add these instance variables into my PagesController#index in order to make the forms work, so many lines become just
#post = Post.new # similar for other objects
#some_other_var = OtherController.new # another one
#one_more = AnotherController.new # again
# even more #variables here when the website is big
If this doesn't seem bad enough, think about when create or edit action fails (e.g. does not pass validation) and we need to render the previous page. We need to add these lines AGAIN. Actually we need to include ALL THESE VARIABLES whenever there's a render.
It seems very cumbersome to manually type such code to every action that needs them and it's so easy to just miss one or two of them when the website gets complicated.
So I'm wondering if there's a better way to manage such variables so that we only need to include them once instead of writing the same code every time.
You can create a before_filter something like:
class ApplicationController < ActionController::Base
...
...
protected
def instance_variables_for_form
#post = Post.new # similar for other objects
#some_other_var = OtherController.new # another one
#one_more = AnotherController.new # again
# even more #variables here when the website is big
end
end
and use it like:
class PagesController < ApplicationController
before_filter :instance_variables_for_form, only: [:action]
...
...
end
and then you can call it explicitly too from any action whenever needed.
If those variables can be logically grouped, you should consider putting them into Presenter objects.
Here is a good blog post explaining the idea: http://blog.jayfields.com/2007/03/rails-presenter-pattern.html

Rails global variable

Im using bootstrap & rails and have a user model and post model..users create posts (collections)..
with bootstrap in the navbar i want the user to be able to click a dropdown which displays the name's of their posts..i did this on one controller with a private method and a before_action but i don't want to do this for all the controllers and it didn't work for the application controller...
is there a better way to do this??
I was doing this
def list
#user = User.find_by_username(params[:id])
#collections = #user.collections
end
and a
before_action :list
at the top of the controller
What's the most semantic way to accomplish this??
If you could move both to your application controller, then it would be available to any controller. More generally, I'm not sure if this is the best approach to solve your problem.
These tips might also be useful.
Are you using devise? Or some other authentication plugin? If so you're likely going to have a current_user helper. This would allow you to simply do #collections = current_user.collections
To the extent possible, I recommend using more descriptive names for your actions and parameters. def fetch_list_collections might be a better name or instead of passing a param named id, perhaps your param should be named username. These naming conventions become extremely important both for others who might look at your code as well as for yourself if you return to it and are trying to remember what you wrote N months ago.
Your list action is generating a N+1 queries. Meaning that you're hitting the database multiple times when you should do so just once. See the rails guide on this. You might also look at ways to avoid this w/ devise. Devise is pretty well documented and I'll bet there is something in the wiki discussing this.
You may want to consider limiting when you call this action - at a minimum - a post request to an update action? What about before they've logged in? current_user might be nil and you'd have an error attempting to call a collections method on nil.
Take your time learning this stuff. You don't have to learn it all at once, but I thought the above might be helpful.
I got it to work with this in the application controller
before_action :list
private
def list
#collections = current_user.collections
end
thanks #arieljuod

Ruby on Rails Controller methods separately?

Just to be educated I wanted to know if it is a good practice to have one controller method for both GET and POST actions, e.g def signup ... end, which would display a form and if request.post? is true - then perform all the business-logic and so on. Is it any good approach, or should I have these methods being separated from each other ?
Thanks in advice!
I think it'll be much better to define a separate action for the post request. You can obviously get it done within the same action, but if you're going to write a big if..else block in sign_up action you may as well use another action. You could call it create if you're short of names :P . It makes the code more logical and readable.
There is little difference in code organisation either way.
With separate methods, it looks like:
def signup_create
# create here
end
def signup_new
# render here
end
With the same method, it looks like:
def signup
if request.post?
# create here
else
# render here
end
end
It looks like they are both reasonably well organised. Choose what your prefer. If they are the default CRUD methods, separate methods are nice, given that there are separate names thought up already (eg. new vs create, edit vs update).
If they are not CRUD, or extra forms on the page, and you can only think of one name for it (like signup), feel free to overload the name and use the same method.
i think that separate actions for different requests are better if u are using(or going to use) method based authorization (eg cancan).

Run ruby script in rails

I made a script in ruby ​​and now I need to run it in a rails application. I'm a little lost, but I have a controller, and wanted through a GET /service /:id returns the result of this script. How can I do this?
By the comments, it seems like you want to make this into a method you can call from your controller.
Simple.
Define the method in the corresponding Model for the Controller you're calling it from (or whatever Model you wish to define the method in) and then call it from the Controller.
Say you have a ScriptRunner model, and you want to call this from the show action of some controller.
In your ScriptRunner model, simply do
def runscript(id)
...
end
and in your controller, do
def show
ScriptRunner.runscript(params[:id])
#service = Service.find_by_id(params[:id])
end
..or whatever you want it to do.
Sergio Tulentsev approach is correct, Just make a model class out of it and call the model method from your controller.
Alternatively which is wrong and hacky you can just call your ruby script directly from the controller
def get
#results = system "ruby your_ruby_script.rb"
end

Resources