Reputation: 924
I have an instance variable @posts_by_month
defined in two controllers and is used in two views:
Posts controller:
class PostsController < ApplicationController
def index
@posts = Post.all
@posts_by_month = Post.all.group_by { |post| post.created_at.strftime("%L") }
respond_to do |format|
format.html # index.html.erb
format.json { render json: @posts }
end
end
.
.
end
Archives controller:
class ArchivesController < ApplicationController
def index
@posts_by_month = Post.all.group_by { |post| post.created_at.strftime("%B") }
end
end
Posts index view:
<h1>Listing posts</h1>
.
.
.
<div>
<% @posts_by_month.each do |millisecond, posts| %>
<p><%= millisecond %>milliseconds <%= posts.count %></p>
<% end %>
</div>
Archives index view:
<% @posts_by_month.each do |monthname, posts| %>
<%= monthname %>
<ul>
<% posts.each do |post| %>
<h3><%= post.title %></h3>
<p><%= post.body %></p>
<% end %>
</ul>
<% end %>
I have two questions. Is there any way I can define the @posts_by_month
instance variable so that I can have it available to both views without repeating it in each respective controller?
Secondly, is there any way that the millisecond part of <p><%= millisecond %>milliseconds <%= posts.count %></p>
can be made into a link that leads to the archive view?
Note: In my app millisecond will be replaced by month as in the archive view.
Upvotes: 0
Views: 1952
Reputation: 4218
Yes you can reduce duplicacy of same variable. One way is to use filters:
Define a mthod inside application controllers:
class ApplicationController < ActionController::Base
private
def find_post_by_month
@posts_by_month = Post.all.group_by { |post| post.created_at.strftime("%L") }
end
end
Then inside archive and posts controllers:
class ArchivesController < ApplicationController
before_filter :find_post_by_month, :only => :index
...
end
class PostsController < ApplicationController
before_filter :find_post_by_month, :only => :index
...
end
This will give you value in @posts_by_month variable.
And, for making link of mentioned text, you should use this code:
<p><%= link_to "#{millisecond} milliseconds", path %></p> # Replace path with your url
Upvotes: 1
Reputation: 24815
When an action was executed, aka rendered, the instance is over. There is no more instance variable.
The instance variables in View are not real instance variables. View and Controller are in different classes, how can they share instance? The reality is, what Rails does is to copy those instance variable from Controller instance to View instance exactly.
So the answer in your question is: No.
But you can still dry your code by a private method in application controller, to share with PostsController and ArchiveController.
class ApplicationController
private
def posts_by_time(arg)
Post.all.group_by { |post| post.created_at.strftime(arg) }
end
end
class PostsController < ApplicationController
def index
@posts = posts_by_time "%L"
# ...
end
end
class ArchievesController < ApplicationController
def index
@posts = posts_by_time "%B"
# ...
end
end
Upvotes: 2