how to detect in which page we are Rails [duplicate] - ruby-on-rails

This question already has answers here:
Best way to highlight current page in Rails 3? -- apply a css class to links conditionally
(8 answers)
Closed 9 years ago.
I am new to Rails.
In my appliction.html.erb, i am using a render partial: to use a html_css shared file.
This shared file contains buttons that can be used by different pages.
For example, for the pages /posts and /answers a search field with a suubmit button taken from the shared filed is displayed.
I would like to make this button work for both pages. When we are in the /posts page, we search in the posts and when we are in the /answers page, we search in the answers.
So, i need to call the right controller each time. For that, i need a helper or a trick that enables me to know in which page i am (which controller#index did i call?).
Does rails contain a method or a helper enabling this?
thanks :)

Use the helper functions: controller_name and action_name.
If you have a controller:
class UsersController < ApplicationController
def my_action
# stuff
end
end
In the view, you can do:
Controller name: <%= controller_name %> <br/> # => users
Action name: <%= action_name %> <br/> # => my_action
See: http://guides.rubyonrails.org/action_controller_overview.html#routing-parameters

Action and controller are in the params already. I imagine you would rather do stuff with that information rather than just display it with controller_name/action_name
for instance to display a footer only in the about page assuming the controller is called about_controller you could
<% if params[:controller] == about %>
<%= render partial: 'footer' %>
<% end %>
params[:action] will contain the action.

Related

Trying to get two actions to have different views, but the same URL

I have an app with shepherds (i.e. the users) and each shepherd has a set of animals. I am trying to make it so that if the logged in shepherd tries to view one of their animals it takes them to a view controlled by the edit action. Alternatively, if the shepherd tries to view another shepherd's animals it gives them a view controlled by the show action. I'd prefer to not have URLs with */edit - I want them to look the same for edit and show. In my routes.rb file I have this...
get '/shepherds/:username/:eartag', to: 'animals#show', as: :shepherd_animal_show
get '/shepherds/:username/:eartag', to: 'animals#edit', as: :shepherd_animal_edit
In the shepherd's show view I create a link to their animals like this...
<% if animal.shepherd == current_shepherd %>
<a href="<%= shepherd_animal_edit_path(username: animal.shepherd.username, eartag: animal.eartag) %>"
<% else %>
<a href="<%= shepherd_animal_show_path(username: animal.shepherd.username, eartag: animal.eartag) %>"
<% end %>
I can see that when I'm logged in and try to access my animals, it goes into the block with the shepherd_animal_edit_path, but it directs me to the show view rather than the edit view. Here's part of the output of the routes...
shepherd_animal_show GET /shepherds/:username/:eartag(.:format) animals#show
shepherd_animal_edit GET /shepherds/:username/:eartag(.:format) animals#edit
I'm a bit of a beginner at Rails and would really appreciate any help people can offer.
I think you should be using the show action for both, and just rendering a different template depending on the animal ownership. I.e.:
def show
...
render 'edit' if animal.shepherd == current_shepherd
# the show template will be rendered automatically if `render` wasn't explicitly called
end
Then in your view, you can unconditionally link to the show action, and the controller will take care of deciding which view template to render.
Also, FWIW, I would probably define the routes as follows:
resources :shepherds, shallow: true do
resources :animals
end
And then use the link_to helper in the view instead of hard-coding HTML tags:
<%= link_to animal_path(animal) %>
But that would then allow you to do other things like:
link_to shepherd_animals_path(#shepherd) # link to the `index` action of `AnimalsController`, with `params[:shepherd_id]` set to `#shepherd.id`.
That would then allow you to render (or not render) other controls for the shepherd to manage his/her own flock if current_shepherd.id == params[:shepherd_id] (or current_shepherd == Shepherd.find(params[:shepherd_id])).

Ruby on Rails layouts and rendering

I'm new to RoR and I'm a little bit confused with Rails MWC. I feel like I misunderstand something.
For example, I want to have home page where I could render top 5 articles and top 5 products. Products and articles have no relations at all, it is totally separate data.
So what I try to do is, i crate 2 sacffolds products and articles, and 1 controller for home page. I root to homepage controller. Then in homepage template i try to render products and article template. I get an error that methods which are used in products and articles controllers are undefined.
I don't understand where is problem. Is this kind of template rendering one template inside another is not Rails convention. Or I have bugs in my code.
I don't see your code but in this case I'm quite sure you have bugs in it.
app/controllers/home_controller.rb
class HomeController < ApplicationController
def index
#products = Product.top5 # Your logic to fetch top 5
#articles = Article.top5
end
end
app/views/home/index.html.erb
<% #products.each do |product| %>
<%= product.name %>
<% end %>
<% #articles.each do |article| %>
<%= article.name %>
<% end %>
This is perfectly fine, I've done that multiple times. Consider that in Rails you don't have any relation between controller and models, there are convention but Rails controller is not bound at all to any model
First, you need to instantiate your variables #products and #articles (this is an example) on your controller method. Then you can render the view.
Pay attention to add an # before. Only variables with an # will be available on your rendering view.
By default, when you call a GET for /products you'll arrive on the index method. At the end of this method, if not any view is specified, Rails will render views/products/index. In this view, you'll access all variables instantiate with an # and do whatever you want with.
First, yes, a template rendering another controller's template (not a partial) is not within Rails conventions.
A scaffold is a "single-resource" controller: it takes your model definition and generates a basic controller for editing and displaying that particular model (i. e., Product).
What you really need to do is use the two models you've generated in the home page controller, kinda like this:
class HomePageController < ApplicationController
def index
#articles = Article.top_5
#products = Product.top_5
# Render the #articles and #products in the view.
end
end

How to display a resource from a different controller?

I'm creating a mostly static home page for a website, except for one little container that needs to pull web links from a model database. The home page view is sitting in home_controller which I created earlier in development. I've now created the link resource and links_controller.
I don't know much about rails and what I've been doing up to now is displaying resources in the index view for their designated controller. However, i need to display this resource in the index view for the home_controller.
Can someone guide me in the right direction towards doing this?
Do a query to fetch the required link objects in the index action of home_controller and display it in the view, as you want:
# HomeController
def index
# other code
# #links = Link.all # or any other query you may want to do
end
# in the view index.html.erb
<% #links.each do |link| %>
<%= link.url %> <br/>
<% end %>
Customize it as per your needs.

Link back to page visited before form

I have a listing page, then a form, then a thank you page. I need to put a link on the thank you page that takes the user back to the page they were on before the form which always varies. I've tried using this:
= link_to "Back", :back
But this only takes them back to the previous page, so the form.
Try this
<%= link_to 'Back', url_for(:back) %>
# if request.env["HTTP_REFERER"] is set to "http://www.example.com"
# => http://www.example.com
here is more details.
Well, you can set a method in the form page to collect that url. The basic idea is to use a custom session variable to store previous url and keep it to next session.
Suppose your form's action is SomeController#new, then
class SomeController < ApplicationController
after_action "save_my_previous_url", only: [:new]
def save_my_previous_url
# session[:previous_url] is a Rails built-in variable to save last url.
session[:my_previous_url] = URI(request.referer || '').path
end
end
Then in the thank you page, you can get this my_previous_url by
session[:my_previous_url]
This should be able to suit your case, the previous url two pages ago.
Disclaimer: This is not verified. Idea only.
Add
Session belongs to controller. It is not a helper you can use directly in view. You need to define an instance variable in controller and then you can use it in view. Like this
# Controller
#back_url = session[:my_previous_url]
# View
<%= link_to "Back", #back_url %>
You can use the example from Rails API:
<%= link_to "Back", :back %>
Rails API Doc for link_to
Using a :back Symbol instead of an options hash will generate a link to the referrer (a JavaScript back link will be used in place of a referrer if none exists).
Since you saying,it might be different page before form, probably request_url can help you. you can save your request_url in a param and redirect to param_url if there is.
here is a source that you can take for reference.
http://programming-tut.blogspot.com/2010/06/ruby-on-rails-request-url.html
If use in Controller, you can direct use like this:
def some_action
# some code
redirect_to :back
end
This works for me:
In controller from previous view:
cookies[:original_referrer] = request.orignal_url
to set a cookie on the browser with the URL of the originating page
In the controller from the current view:
redirect_to cookies[:original_referrer]

Render view from application_controller

So, I have search form, and search is avaliable obviously from any page.
I thought that it makes sense, that such action from application controller is placed in layouts/views folder.
But I just don't get- Rails doesn't see it. So I can't do this? How then should I provide action, avaliable from any page?
Code:
def tests_search
#tests=Test.test_search(params[:query])
respond_to do |format|
format.html
end
end
Route:
search_tests GET /search_tests(.:format) application#tests_search
Form:
<%= form_tag search_tests_path, {:id=>'test_search',:method => :get} do%>
Error:
Unknown action
The action 'tests_search' could not be found for ApplicationControllerr
You should create a new search controller. Use rails g controller search index which will create a search controller with a index action (you could also call the action something like result). Then add a search/_form.html.erb file in your search view folder, with the form:
<%= form_tag search_path, {:id=>'test_search',:method => :get} do |f| %>
and render this in your layout/application.html.erb where you want it to be:
<%= render "search/form" %>
This way you have a search form on any pages, that uses the SearchController to handle the search requests.
I would recommend using other controller to do this. It can be for example SearchController even if there will be only one method.
Notice that ApplicationController is controller that every other controller in application inherits from by default. So if it wouldn't be the case, it could make sense, but now every controller will inherit your test_search action, which is not desired.
If your search form will be a partial, then there is no difference whether this is in ApplicationController or in any other controller. You just have to point to right route.
Initially you have to explain yourself the flow. What you need is some partial which is rendered on all pages, and if a user adds some input to it and submits, he gets some output. Right? Good. So you start by creating a new partial somewhere in
app/views/shared/_search.html.erb
Then, you create your route in routes.rb to point to a controller's action. You don't have to place this in application_controller. Instead, create your search_controller.rb and create some action which responds to the form submission there.
Whenever you want to render your search form on other pages, you simply call render partial (more on that here) with something like
<%= render "shared/search" %>
This is good if you created the file above. Make sure your action exists and the name is correct, in your case it should be:
def test_search
...
end
Good luck.

Resources