Current controller path without specifying a action in rails - ruby-on-rails

I have a rails application that has 2 menu in which the menus changes depending on what page the users are currently visiting. Is there any way to tell rails that if a user is visiting this controller, no matter if the visitor is on the index,edit,create,update,delete method?
I am currently using a helper like so it and it indeed a bit messy.
def which_page
current_page?(root_path) ||
current_page?(skate_movies_path) ||
current_page?(new_skate_photos_path(#user)) ||
current_page?(skate_photos_path) ||
current_page?(skate_tricks_path)
end
In My view partial
<% if which_page %>
<%= default_menu %> #upload, #photos, #trick-tips, #goals
<% else %>
<%= skate_menu %> #dashboard, #shared-videos, #profile
<% end %>
The problem is this works but throughout the application I always find a page or two where it gives me a routing error. Any way to tell what controller the user is on and action without specifying ever action?

You could define a before_filter in your ApplicationController and name it set_menu
class ApplicationController < ActionController::Base
before_filter :set_menu
protected
def set_menu
#menu = 'default'
end
end
Then in each controller that you want to show a different menu for you would override set_menu, for example:
class SkateMoviesController < ApplicationController
protected
def set_menu
#menu = 'skate'
end
end
you could use the helper method action_name in set_menu to access the current action in the controller.
Then in your views:
<% if #menu == 'default' %>
<%= default_menu %>
<% else %>
<%= skate_menu %>
<% end %>

Related

Display different indices depending on the scope

I have an Orders index page with two links, whose indices I want to filter by the status of the order:
<%= link_to "Current Orders", orders_path(:by_status => "processing") %>
...
<%= link_to "Past Orders", orders_path(:by_status => "completed") %>
My controller looks like:
class OrdersController < ApplicationController
has_scope :by_status
def index
case params[:status]
when "completed"
#past_orders = Order.where(status: "completed")
when "processing"
#current_orders = Order.where(status: "processing")
end
end
end
I'm sure def index is the main problem. But I also can't figure out how to display that in the view page. I have:
<% #past_orders.each do |order| %>
I would appreciate the help.
to solve your problem you can split the render based of your condition from index.html.erb
in index.html.erb create condition if #post_orders has contents then render past_orders else render current_order
<% if #post_orders %>
<%= render 'past_order.html.erb' %>
<% else %>
<%= render 'current_order.html.erb' %>
<% end %>
then you create two partial file with name _past_order.html.erb and _current_order.html.erb put in same folder with index.html.erb
If you want the view to look the same for both scopes then you should handle it at the controller. It looks like you're using the has_scope gem, so this should work:
class OrdersController < ApplicationController
has_scope :by_status, only: :index
def index
#orders = apply_scopes(Order)
end
end
You need to have a matching scope method on the Order model
class Order < ApplicationRecord
scope :by_status, ->(status) { where status: status }
end
In your view orders/index.html.erb you would handle the collection exactly the same way, using #orders for both current and past orders
<% #orders.each do |order| %>
If you ever need to display a component of the view differently depending on the order status just add an if statement
<% if order.status == "completed" >
<p>Something<p>
<% else >
<p>Something else<p>
<% end >

Rendering view from different controller NilClass Error

I'm trying to render a view in a different controllers view but I'm getting:
undefined method `each' for nil:NilClass
I'm rendering the view in 'views/users/show' as:
<%= render :template => 'groups/index' %>
The view itself is under 'views/groups/index':
<% #groups.each do |group| %>
<li>
<%= group.name %>
<%= group.description %>
</li>
<% end %>
And my groups controller for index looks like this:
def index
#groups = Group.all
end
I think it's a problem with how i'm rendering the view since if I make an instance variable in my index controller and call it in the view it won't appear. There are entries in the Group table in my database.
Any help would be appreciated.
Thanks in advance.
I think it should be enough to replace the template: with a partial: parameter.
Try this:
<%= render partial: 'groups/index' %>
You will have to rename/copy groups/index.html.erb with groups/_index.html.erb
This only works for rendering a view, but will not implement the functionality of your GroupsController.
Edit
You will have to redefine the groups inside your UsersController
# UsersController
def index
#groups = Group.all
end
Depending on how many times you will need to present all these groups to your user, this can become hard to maintain. If you use it frequently, consider adding
# i.e. ApplicationController
def groups
Group.all
end
inside your ApplicationController (or some module you want to include in different controllers). Then you could call
# UsersController
def index
#groups = groups
end
and still <%= render partial: 'groups/index' %>
Change:
<%= render :template => 'groups/index' %>
To:
<%= render 'groups/index' %>
and make sure the file name of your index action is _index.html.erb and not index.html.erb.
EDIT
When you render a view, you are only rendering the template, this does invoke a request on your index action. You must define #groups in your initial view's action.

Interpolating data in a rails view

I'm a beginner at rails and thus far interplating data in views has been pretty straight forward. I've been introduced to something slightly new as far as how the controllers are setup and as a result I'm not sure how one would go about getting the data to present in the view.
First controller
class PagesController < ApplicationController
def index
#guestbook_entry = GuestbookEntry.new
render "welcome"
end
end
Second controller
class GuestbookEntriesController < ApplicationController
def create
GuestbookEntry.create(guestbook_entry_params)
redirect_to root_path, notice: "Thank you for your entry."
end
private
def guestbook_entry_params
params.require(:guestbook_entry).permit(:body)
end
end
And here is the welcome.html.erb
<h1>Welcome to My Guestbook</h1>
<br>
<%= image_tag("under_construction.gif") %>
<div id="guestbook-entries">
<p>Guestbook Entries:</p>
<ul>
</ul>
</div>
<%= form_for #guestbook_entry do |f| %>
<%= f.label :body, "Guestbook Entry:" %>
<%= f.text_area :body %>
<%= f.submit "Submit" %>
<% end %>
So it wants me to iterate through all the entries and display them on a welcome page that's located in view/pages/welcome.html.erb.
Up to this point I guess I've only been doing basic simple rails applications where the view corresponded with the controller, and followed the typical CRUD setup, where index would hold the #xxx = Xxxx.all and new/create would handle #xxx = Xxxx.new/create/build. I thought I could simply move the PageController's index action to create/new and do
def index
#guestbook_entry = GuestbookEntry.all
render "welcome"
end
To satisfy the test (it looks for render welcome in the index action)
This seems weird but again I admit, I'm a beginner.
If you want to list all the guest book entries on your root page you would do something like:
class PagesController < ApplicationController
def index
#guestbook_entry = GuestbookEntry.new
#guestbook_entries = GuestbookEntry.limit(10).all
render "welcome"
end
end
And in your view you would list them like:
<% if #guestbook_entries.any? %>
<div id="guestbook-entries">
<p>Guestbook Entries:</p>
<% #guestbook_entries.each do |entry| %>
<ul>
<li class="entry"><%= h(entry.body) %></li>
</ul>
<% end %>
</div>
<% end %>
The rest of you application is correct - you should be creating entries in GuestbookEntriesController#create. In many real life applications then the functionality of the standard new and edit actions can actually be a totally different controller.

Rails make record available to application view

I've got a module that lists events (event_box) and I want to define it as part of my application.html.erb:
<div id="left_sidebar">
<%= render 'shared/user_box' %>
<%= render 'shared/event_box' %>
<%= render 'shared/server_info_box' %>
</div>
However, the event_box uses #events, which so far needs to be passed to it:
def home
#events = Event.all
end
If it's going to be in the application layout, how do I pass #events to it without defining #events in every view in my application?
Define a method in ApplicationController which fetches all the events.
Use this method as a before_filter in ApplicationController. Filters called in ApplicationController will apply to all the controllers inheriting from it.
application_controller.rb:
before_filter :fetch_events
def fetch_events
#events = Event.all
# #events = Event.where({}) can be used to lazy load the events
end
Since this is going to be executed before every action, consider using Fragment caching for that particular portion of the view.
You can try below code also in shared/event_box partial. It will work.
<% #events = Event.all %>
<% #events.each do |event| %>
<p><%= event.column_name %></p>
<% end %>

link to nested comment 'edit' action from parent articles controller 'index

I am trying link to the 'edit' action of a nested Comment from the 'index' action of its parent Articles controller. If no comment exists, then the link will go to the 'new' action.
resources :articles do
resources :comments
end
The problem seems to be how to define #comment in the Articles controller in order to get the proper comment id with the associated article id.
The Articles controller contains:
def index
#articles = Article.all
end
I can accomplish what I want by defining #comment in the View 'index.html.erb' (see below):
<% #articles.each do |article| do %>
<% #comment = current_user.comments.where(article_id: article.id) %>
<% if #comment.empty? %>
<%= link_to "New Comment", new_article_comment_path(article) %>
<% else %>
<% #comment.each do |comment| %>
<%= link_to "Edit Comment", edit_article_comment_path(article, comment) %>
<% end %>
<% end %>
<% end %>
But I would prefer to have #comment defined in the Articles controller. I am not sure how to implement '#comment = current_user.comments.where(article_id: article.id)' in the Articles controller without the id as it's the 'index' action.
Must be something simple I'm missing.
I don't know how it would work inside a controller. But I think it's better to move the method inside a helper anyway and call it from there. methods defined inside a helper are automatically available for your views
you can do this:
def comment(article)
#comment = current_user.comments.where(article_id: article.id)
end
Then your view will look like this:
<% #articles.each do |article| do %>
<% comment(article) %>
....more code....
Like you said, if you move this in the controller, where(article_id: article.id) will trip you as you don't know which article the id is bound to.
EDIT:
if you really want to access the method inside the controller, you can do as this post suggests:
class ArticlesController < ActionController::Base
def comment(article)
#comment = current_user.comments.where(article_id: article.id)
end
helper_method :comment(article)
end
but why go through the trouble when you can easily do this inside a helper.

Resources