Where to define Rails variable in application.html.erb - ruby-on-rails

I have a navbar that is placed in the /views/layouts/application.html.erb and in there I place the #buy and #sell variables which get the latest bitcoin price. They are currently placed in the /welcome controller so the prices only show when in the welcome controller. If I navigate to another controller, the bar just becomes empty.
#buy = coinbase.buy_price
#sell = coinbase.sell_price
That is the code that is currently placed in the welcome controller. I want it to be available to the navbar regardless of what controller the user is in. Any help would be great!

place it in the application controller and use a before action
before_action :set_prices
def set_prices
#buy = coinbase.buy_price
#sell = coinbase.sell_price
end

Two ways:
Write the code in application_controller as before_filter, and use the variables in nav bar.
before_filter :prices
def prices
#buy = coinbase.buy_price
#sell = coinbase.sell_price
end
Write the code in application.html.erb, just before the nav bar code:
<% #buy = coinbase.buy_price %>
<% #sell = coinbase.sell_price %>
And use them directly.

Related

ActiveAdmin - set dynamic title panel/sidebar

I haven't been able to find a clear answer in the ActiveAdmin docs, or elsewhere. Is there a way to dynamically set the title of a panel or sidebar? For example, I need to have the name of the resource that I'm filtered to included in the title. Is that possible?
panel "#{resource.name}", class: "panel_with_resource_name" do
.....
end
or maybe you are looking for this?
controller do
before_action {
#title = " #{Model.find(params[:your_object_id]).try(:whatever_params)}"
}
end
or
controller do
def whatever_action
#title = "this is"+resource.name
end
end
then in view
whatever_action:title=> #title do
.....
end

Available approaches for layouts when only the navigation depends on the controller

Given a layout with a navigation bar which depends on the current controller :
# layout.html.slim
doctype html
html
body
main
= render partial: 'domain_nav'
= yield
The app has several business domains, let's say "Clients", "Tasks", "Books", with their own distinct navigations (clients_nav, tasks_nav, books_nav).
Each part has several controllers, and the view will display the navigation based on the controller business domain (e.g. the Clients::CompaniesController will display the clients_nav).
The html above is simplified but basically, all controllers share the same layout except for the domain_nav which depends on the domain.
I see several ways to handle that :
use a helper and determine which nav to use based on the controller
name : this means editing the helper each time a new controller is
introduced, it doesn't feel right
use content_for :navigation in each view and yield :navigation : since we're sure that the navigation is displayed for each view,
this doesn't feel right either
use a sub layout per section and call render layout: 'clients/layout' do : it works but then i18n becomes a mess
define one layout per domain : not very DRY
use a single layout and define which nav (partial name) to use in the controller : that partial name would be set using either
inheritance (have one controller per domain that sets the nav partial
name) or concerns
define a layout per domain (setting the layout in each controller) but render them using a shared layout as shown below
# layouts/_shared.html.slim
doctype html
html
body
main
= render partial: nav_path
= yield
# layouts/clients.html.slim
= render partial: 'layouts/shared', locals: { nav_path: 'clients/nav' }
# layouts/tasks.html.slim
= render partial: 'layouts/shared', locals: { nav_path: 'tasks/nav' }
# layouts/books.html.slim
= render partial: 'layouts/shared', locals: { nav_path: 'books/nav' }
Are there other approaches to this problem ? Which one would you pick and why ?
If controllers could be grouped by their namespace as like their navigation name, I will go with the "use a helper and determine which nav to use based on the controller name" approach. Like if a controller name starts with Clients (for example, Clients::CompaniesController) we could easily map it to clients_nav.
def nav_path
if params[:controller].starts_with? "Client"
'clients/nav'
elsif params[:controller].starts_with? "Task"
'tasks/nav'
else
'books/nav'
end
end
If you cant group controllers by such namespace, you could still go with a different variation of this approach only if you have an admin panel. We could create a table which map controller_name to navigation_path. Entries on this table could be populated from admin panel only.
I went a different way. Since it's the responsibility of the controller to decide of the layout, I thought it would be the rails way to let it also decide of the navigation.
So just like there is a "layout" declaration, I now have a "navigation" declaration. Here's what the controllers look like:
class ClientsController < ApplicationController
navigation 'clients/nav'
…
end
class BooksController < ApplicationController
navigation 'books/nav'
…
end
and I have just one layout:
doctype html
html
body
main
= render partial: navigation
= yield
The navigation method is declared in ApplicationController:
class ApplicationController < ActionController::Base
helper_method :navigation
def self.navigation(path)
define_method :navigation do
path
end
end
end

Display navbar on all pages except home page

I want to show two different navbars. One will be displayed, on all pages except home page, when you're logged in. While the other navbar will be displayed just on my landing page.
I am thinking that I will probably need to write an if statement.
If (current user is not logged in) or maybe (current user is viewing home page) do
<nav>Second navbar</nav>
else
<nav>First navbar</nav>
end
I am very new to rails, so I could be wrong. (And yes, I know that's not how to correctly write an if statement in Ruby)
Home page is located at:
home/index.html.erb
I normally do following setup:
create partial shared/_nav_menu.html.erb
inside partial I put logic like:
<% if current_user %>
// nav bar for logged in user
<% else %>
// nav bar for non logged in users
<% end %>
Then inside application.html.erb file I render the partial like this:
<%= render :partial => 'shared/_nav_menu' if show_menu? %>
Inside my application_controller I put logic like this:
def show_menu?
true
end
helper method: show_menu?
If I don't want to show the menu for static_pages then inside static_pages_controller I overwrite show_menu? method to return false.
class StaticPagesController < ApplicationController
def show_menu?
false
end
helper_method: show_menu?
end
You don't have to use exactly this setup but I like this setup because my nav menu logic is kept seperate in partial. All logic required to nav menu lives in this file.
This approach don't bloat my application.html.erb file with lots of if..else.
In the case of two menus, but leaving yourself open to more, I would use a similar-but-slightly-different approach than Reboot's answer.
In the layout:
<%= render :partial => #nav_bar_partial %>
Then in my application controller, define the default nav:
def standard_nav
#nav_bar_partial = "path/to/standard/nav/partial"
end
From there, you can override that nav partial any time you need to (with any partial you want) from your controller
#nav_bar_partial = "path/to/new/nav/partial" if condition_that_requires_a_different_nav
That way, you have a little more flexibility. If for some reason you want to add a third nav bar for some other condition, you can just override the partial elsewhere without changing any of the above code.
You can prepare two layouts, one for the landing page and another for rest of the pages. Take a look at the official documentation: http://guides.rubyonrails.org/layouts_and_rendering.html.

Rails application view isn't displaying what i want

I'm probably doing something really stupid but i'm unsure what i'm doing wrong.
I'm making a counter that sees how many times the user has been on the index page in their current session.
The following is in a store_controller.rb
class StoreController < ApplicationController
def increment_counter
if session[:counter].nil?
session[:counter] = 0
end
session[:counter] += 1
end
def index
#products = Product.order(:title)
#counter = increment_counter
#counter_msg = "You've visited this page #{pluralize(#counter, "time")}"
end
end
And the following here is in application.html.erb layout view.
<%= #counter_msg %>
Of course with other code but that seems irrelevant for now.
Nothing at all is displayed from #counter_msg
What am i doing wrong?
Thanks.
pluralize is a helper method. You must use the line bellow in application.html.erb
<%= "You've visited this page #{pluralize(#counter, "time")}" %>
or, include helper in your controller:
include ActionView::Helpers::TextHelper
The pluralize method is a view helper and should be called from inside the view. Also views are exactly designed for this purpose so a display string should be in the view anyway.
<%= "You've visited this page #{pluralize(#counter, "time")}" %>
Delete the #counter_msg line from the controller.
It's looking like you are calling method in wrong place, if you want to show #counter_msg then it should be defined inside application controller first include helper
include ActionView::Helpers::TextHelper
into controller
also, the current code is telling you can use your variable inside store index page.

Rails rendering a different view depending on the controller

I have a tab navigation page in my rails app which is shared across all of my views. Inside I have a small text area which should change depending on the page that the user is on.
Currently I am doing this by adding a variable to the controller and using it in the render partial path, like so:
class Myapp::WebsitesController < MyappController
def set_up
#page = 'websites/left_text_info'
end
and then in my partial:
<%= render :partial => #page %>
This works but it doesn't feel like the best 'ruby' way of doing things. Can anyone advise on a better way of doing this?
Thanks
You can use controller_name helper method directly in your view and skip the controller part:
<%= render "#{controller_name}/left_text_info" %>
Or if the only thing that change is the content of the textarea, then perhaps the best way is to define a helper method that returns only the content for it, so you don't need multiple partial files that are very similar.
module ApplicationHelper
def text_area_content
case controller_name
when "users"
"content for users"
when "articles"
"content for articles"
else
"other content"
end
end
end

Resources