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.
Related
I'm wondering how to create a "shuffle" button in the header partial of my rails app that links to a random record. I have a "pins" table and each pin is a video.
I've searched through stackoverflow and couldn't figure out how to do it..
I think it had to do with the header partial doesn't work with the Pins controller/model.
When someone clicks the button it should link to something like this:
website.com/pins/13
Any help would be great thanks!
EDIT:
This is the code I have previously tried:
offset = rand(Model.count)
rand_record = Model.first(:offset => offset)
But I am new to rails and I wasn't sure where to put it. I tried putting it in the model and the controller and both didn't work.
Ok, so I'm assuming that you want a link to a random Model to be shown each time a user loads a particular page. Let's say that the page that shows this link is the ModelController#index action.
Since the randomization only happens when the page is initially loaded, you can do it in the controller action:
class ModelController < ActionController::Base
#other actions
def index
#any other index code
#random_model = Model.order('random()').first
end
end
Now, in your view, you can link to that model in the usual manner:
<%= link_to("Shuffle", #random_model, :class => "btn btn-small btn-warning") %>
Every time that the controller action executes, it will pick a Model at random, and include a link to that Model when it renders the page.
Edited to address:
"Is there anyway to make it work without putting the code in the index and show actions?"
Yes. You can actually load the model right in the view code. Normally, assigning it to an instance variable in the controller is the 'more correct' method, but as you point out, it leads to duplication of code. If this is something you want to include in multiple views, I would recommend making it a partial. Something like so:
views/shared/_shuffle.erb:
<%= link_to("Shuffle", Model.order('random()').first, :class => "btn btn-small btn-warning") %>
And then rendering that partial in any page you want to include a randomized link:
<%= render 'shared/shuffle' %>
Note that if you render this partial more than once in a page, the random model will be different for each link.
I have a Home page with 2 Bootstap tabs. I'm having problems with the 2nd tab. I'm trying to render a list of workorders. For that list I'm using dataTables and ajax.
My issue is that workorders/index7.html.erb works fine as a stand alone page. But, I want to use it in a Bootstrap tab on the Home page.
For all my other Bootstrap tab lists, I'm using partials from within the same controller. But, in this case, I need to use a view from the Workorder controller not the Home controller.
This is the code I'm trying in the Home view:
<div class="tab-pane" id="tab2">
<%= render "workorders/index7" %>
</div>
That code gives me:
Missing partial workorders/index7
WHY? If I change the file name to _index7.html.erb the code won't execute to get the json.
But, because it's a partial, starting with _, the connection to the Workorder controller code for index7 doesn't work. I also tried _index7 in the Workorder controller.
The Workorder controller has this code:
def index7
#workorders = Workorder.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: Workorders3Datatable.new(view_context) }
end
end
That code uses a file called workorders3_datatable.rb to get the data via ajax and format it for dataTables.
QUESTIONS:
1) Do I have to use a partial in the Home tab? Or is there a way to render a file called workorders/index7.html.erb in the tab?
2) Why does index7.html.erb use the controller code for index7, yet the partial _index7.html.erb won't use code if I call it _index7 in the controller?
3) I read this "Render will just render the view, it won't run the action associated with it." - is that true?
Thanks for your help - I know this is confusing.
Reddirt
UPDATE 1
The view runs great as workorders/index7 - but, if I change it to a partial and put it in a tab = workorders/_index7 - the controller code for index7 doesn't seem to execute.
1) Do I have to use a partial in the Home tab? Or is there a way to view a file called workorders/index7.html in the tab?
If you want to follow this approach. From Home controller pass the collection (#workorders = Workorder.all)
Then in the home view pass it to the workorders/index7 as locals
<div class="tab-pane" id="tab2">
<%= render "workorders/index7" locals: {workorders: #workorders} %>
</div>
This will make it available to workorders/index7 do remember to change the variable to a local variable workorders.
You need to include :partial in the view for your Home page:
<%= render :partial => "workorders/index7" %>
The app/views/workorders folder will need a file called _index7.html.erb. To accomplish this from your current setup, you can move the contents of index7.html.erb into this partial, and then use:
<%= render :partial => "index7" %>
in the original index7.html.erb. That way you can render that as a whole page and within your Home page as a partial.
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.
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
I'm using the same layout for several controllers, and inside this layout I include a menu using a call to a helper, like this:
<%= side_menu %>
What I'd like to do is vary the contents of side_menu depending on the controller that's invoking the layout. In an ideal world, I could define side_menu in application_controller.rb and in other helper files and then the appropriate helper would be selected depending on the controller; in other words, something like this:
# application_helper.rb
def side_menu
"generic menu This goes here"
end
# users_helper.rb
def side_menu
"menu for users goes here"
end
# guests_helper.rb
def side_menu
"menu for guests goes here"
end
This doesn't work because in Rails 3 all helper files are loaded and I have no control over which side_menu will actually be called. It would be great if there were an option to load only application_helper.rb and the controller-specific helper, but there's not one (yet).
What's the best way to vary the content of a helper depending on the controller? I'm currently defining side_menu once in application_helper.rb and then checking to controller to see what to add. This feels wrong, since the problem nearly screams for a subclass-and-override answer -- which I can't do due to the "helper :all" behavior of Rails 3. Suggestions?
You can define this method in controller and add:
helper_method :side_menu
But maybe different solution would be better. I think that you can add _side_menu.html.erb in each controllers view folder and when you call <%= render :partial => 'side_menu' %> it should look for different files depending on current controller (however rememeber to add this file for all controllers).
Or you can mix these two methods. Add this helper method to controller and inside it render right file. This way it is better, because you get some default side menu and it won't crash when there is no side menu partial for a controller.
You can also in layout add <%= yield :side_menu %> and if you want to put something in side menu, just add <% content_for :side_menu do %> bla bla bla <% end %>.