I'm new in ruby on rails, and I want to practice it.
I'm stuck when I want to include a view into antoher view.
I want by doing that to have my posts into another view than of posts/index
posts/index
method:
def index
#Posts = Post.all
end
view:
<% #posts = capture do %>
<% #posts.each do |post| %>
<h3>
<%= post.title %>
</h3>
<p>
<%= post.content %>
</p>
<% end %>
<% end %>
pages/index
<h1> Index Of another pages </h1>
<%= #posts %>
If you want to force your index action to render another view, then go with follow code:
def index
#Posts = Post.all
render 'pages/index'
end
Correct me if I haven't get you
It sounds to me like you need to save the reusable view code as a partial, and render it all places it's required.
To use a partial, save it down with an underscore prefix, i.e. _posts.html.erb.
This can then be rendered using:
<%= render 'path/to/posts' %>
You'll likely need to pass in the posts variable to the partial, as in the following:
<%= render 'path/to/posts', posts: #posts %>
And the change your view to use posts rather than #posts.
Update:
The result of capture is assigned to #posts, although this variable still wouldn't be available in another template - rather to be used again on the same page
Based on what you're saying about the project's structure, it sounds like you'd need the following:
in app/views/posts/_posts.html.web
<% #posts.each do |post| %>
<h3>
<%= post.title %>
</h3>
<p>
<%= post.content %>
</p>
<% end %>
In both controllers' index action:
#posts = Post.all
In the posts/index view:
<%= render 'posts' %>
In the pages/index view:
<%= render 'posts/posts' %>
I don't want to confuse things, but Rails has a little magic in there where -
alternatively - you can define a partial _post.html.erb as follows:
<h3>
<%= post.title %>
</h3>
<p>
<%= post.content %>
</p>
And simply call <%= render #posts %> in each view. This would be the best 'Railsy' way of doing things.
Let me know how you get on!
Related
I've got an index page with a search which mostly works, aside from when there are no results, which is when I get the error:-
response has no matching <turbo-frame id="events"> element
I don't get this when there are search results. Do I need to specify a partial to render in my index action, when results are empty? Why isn't this being evaluated in my view?
index.html.erb
<div id="events-wrapper">
<% if #events.any? %>
<%= render "events", events: #events %>
<% else %>
<%= render "no_events" %>
<% end %>
</div>
_events.html.erb
<%= turbo_frame_tag "events" do %>
<%= render collection: #events, partial: 'event' %>
<%= raw pagy_bootstrap_nav(#pagy) %>
<% end %>
_no_events.html.erb
<div class="no-events-notice alert alert-primary">
No events found
</div>
events_controller.rb index action
def index
#pagy, #events = pagy(find_events(filter_params))
end
Basically my search works fine, but when there are no results - my no_events partial doesn't get rendered, unless I refresh the page. What am I missing?
I've removed the partial from the equation and just replaced that line with a simple div instead and it's still not displayed.
The solution was to wrap the results in a turbo frame with an id of "events" like so:-
<turbo-frame id="events">
<% if #events.any? %>
<%= render "events", events: #events %>
<% else %>
<%= render "no_events" %>
<% end %>
</turbo-frame>
This is driving me crazy, I thought it should be something very simple but I've spent all day trying to figure it out and getting nowhere. I've looked all over, there's something I must be missing.
I want to render a partial for a collection, within a partial from a collection.
Eg. I have a collection of entries which I want to render in my feed partial, I want feed to come from a collection of feeds, such that the page displays all entries in all feeds.
How can I do this?
Something like:
controller:
#feeds = Feeds.all
allmyfeeds.html.erb
#feeds.each do |feed|
<%= render 'feed' %>
<% end %>
or
<%= render 'feeds', collection: #feeds %>
_feed.html.erb
<%= render 'items', collection: #items %>
_item.html.erb
<%= item.summary.html_safe %>
But I really don't know.
Partial naming conventions will really help you out here...
In allmyfeeds.html.erb (which i'm guessing is actually feeds/index.html.erb), instead of this...
#feeds.each do |feed|
<%= render 'feed' %>
<% end %>
You can simply call this...
<%= render #feeds %> # this will invoke _feed.html.erb for every feed in the collection, automatically
Inside your _feed.html.erb partial...
# Note: You may need to change `items` to something like `items/items` if it is not located in the same directory
<%= render partial: 'items', locals: { items: feed.items } %>
Then in your items partial, you will have access to items, which is a collection of items for that particular feed
Somehting like:
<% #feeds.each do |feed| %>
<%= render partial: 'feed', locals: { feed: feed } %>
<% end %>
In your _feed.html.erb:
<h1><%= feed.id %> </h1>
<% feed.entries.each do |entry| %>
<&= render partial: 'entry', locals: { entry: entry } %>
<% end %>
In your _entry.html.erb:
<h2><%= entry.id %></h2>
I'm assuming your Feed model has a has_many :entries association, if it's not the case (and what you want is to render the same collection of #entries in each feed), then you just need to pass the #entries collection to the _feed.html.slim partial, like:
render partial: 'feed`, locals: { feed: feed, entries: #entries }
and update your _feed.html.erb
Is it possible to make small changes in different views?
The same partial is rendered in index.html.erb and show.html.erb as below.
index.html.erb
<%= render #schedules %>
show.html.erb
<%= render #schedules %>
What I'd like to do is not to display some value in the index.html.erb. (and display some value in both erb)
For example, I'd like to display start_at and end_at only in show.html.erb and display title in both erb.
_schedule.html.erb
<% schedule.rooms.each_with_index do |a, idx| %>
<% a.events.each do |e| %>
<%= l(e.start_at) %>-<%= l(e.end_at) %> # display only show.html.erb
<%= e.title %> #display both erb
...
<% end %>
...
<% end %>
Althogh I come up with idea which I create two partials, it contradicts the DRY policy.
It would be appreciated if you could give me any idea.
You can use controller.action_name.
<% if controller.action_name == 'show' %>
<%= l(e.start_at) %>-<%= l(e.end_at) %> # display only show.html.erb
<% end %>
The params hash also contains the action_name.
action_name is enough and do the trick but personally I don't like this. I'd do two separate partials.
Can check current action and current controller on page. So we can call single partial from different actions and can customize as per action name or action and controller name.
eg.
<% schedule.rooms.each_with_index do |a, idx| %>
<% a.events.each do |e| %>
<% if #current_controller == "events" and #current_action == "show" %>
<%= l(e.start_at) %>-<%= l(e.end_at) %> # display only show.html.erb
<% end %>
<%= e.title %> #display both erb
...
<% end %>
...
<% end %>
Also need to update Application Controller.
class ApplicationController < ActionController::Base
before_filter :instantiate_controller_and_action_names
def instantiate_controller_and_action_names
#current_controller = controller_name
#current_action = action_name
end
end
You could use CSS to hide/show the content based on context.
In practice, I have found this a good way to reuse partials that have small differences. Especially when those differences don't cost anything to compute i.e. printing a date
You can cache the partials without worrying about where they are rendered
Reduce conditional logic
Remove duplication
<% if controller.action_name == 'show' %> is fine for a simple use case. If/When you come to have multiple places where the partial needs to be rendered, it will become unwieldy. The CSS solution would only require another wrapper <div class="schedules--whatever"> and the related CSS style.
show.html.erb
<div class="schedules--show">
<%= render #schedules %>
</div>
index.html.erb
<div class="schedules--index">
<%= render #schedules %>
</div>
_schedule.html.erb
<% schedule.rooms.each_with_index do |a, idx| %>
<% a.events.each do |e| %>
<div class="event__date">
<%= l(e.start_at) %>-<%= l(e.end_at) %>
</div>
<%= e.title %>
...
<% end %>
...
<% end %>
schedules.css
.schedules--show .event__date {
display: block;
}
.schedules--index .event__date {
display: none;
}
I'm trying to create a helper method that will display {user.name} has no submitted posts." on the profile show view of user if they haven't yet submitted any posts and display the number posts they have . currently on my show view i have <%= render #user.posts %> which displays nothing when there are 0 posts submitted.
the partial for post is :
<div class="media">
<%= render partial: 'votes/voter', locals: { post: post } %>
<div class="media-body">
<h4 class="media-heading">
<%= link_to post.title, topic_post_path(post.topic, post) %>
<%= render partial: "labels/list", locals: { labels: post.labels } %>
</h4>
<small>
submitted <%= time_ago_in_words(post.created_at) %> ago by <%= post.user.name %> <br>
<%= post.comments.count %> Comments
</small>
</div>
</div>
ive tried :
def no_post_submitted?(user)
user.post.count(0)
"{user.name} has not submitted any posts yet."
end
on my user show view :
<%= if no_post_submitted?(#user) %>
<%= render #user.posts %>
which im more than sure is wrong but i have no idea how to implement this method .
Where you are using render #user.posts you can just add a simple conditional:
<% if #user.posts.empty? %>
<p><%= #user.name %> has no submitted posts</p>
<% else %>
<%= render #user.posts %>
<% end %>
There wouldn't be much point creating a helper for this unless you need to use it in multiple places.
Render collection returns nil if the collection is empty so you can use the || operator:
<%= render #user.posts || "{#user.name} has not submitted any posts yet." %>
Or if there is more code render another partial:
<%= render #user.posts || render 'no_posts' %>
In Ruby methods automatically return the last value so this method:
def no_post_submitted?(user)
user.post.count(0)
"{user.name} has not submitted any posts yet."
end
Will always return a string - if you use a string literal in a condition it will be evaluated as true with the warning warning: string literal in condition. Also that is not how you use count - passing 0 will cause it to query on column 0 or just error.
http://apidock.com/rails/ActiveRecord/Calculations/ClassMethods/count
So to fix the method you would do:
def no_post_submitted?(user)
user.posts.empty?
end
However that conditional is so simple that it does not really warrant a helper method. Instead you would just write:
<%= if user.post.any? %>
<%= render #user.posts %>
<% else %>
<%= "{user.name} has not submitted any posts yet." %>
<% end %>
There are a couple of problems with your solution. Remember, rails is more about convention over configuration.
Your method no_post_submitted? should actually return true/false since its a method ending with ?. Also it should be named no_posts_submitted? for clarity. It should look something like this:
def no_post_submitted?(user)
user.posts.count > 0
end
Then, there should be another helper method that will print your required message, Something like:
def no_posts_message(user)
"{user.name} has not submitted any posts yet."
end
And eventually you can all plug it in like this:
<% if no_posts_submitted?(user) %>
<%= no_posts_message(user) %>
<% else>
<%= render #user.posts %>
<% end %>
As per the docs:
In the event that the collection is empty, render will return nil, so it should be fairly simple to provide alternative content.
<h1>Products</h1>
<%= render(#products) || "There are no products available." %>
--
So...
<%= render(#user.posts) || "#{#user.name} has not submitted any posts yet." %>
I've got this working now quite accidentally, but I don't understand what causes it to break when I explicitly specify what partials are to be used for rendering the resource/s. Can anyone explain it?
The index template for my Posts controller contained the following line, which was giving me an error:
<%= render partial: 'posts', collection: #posts %>
The error (in my browser) said:
NoMethodError in Posts#index
Showing /Users/applebum/Sites/rails_projects/eventful2/app/views/posts/_posts.html.erb where line #1 raised:
undefined method `any?' for #<Post:0x000001064b21f0>
Extracted source (around line #1):
1: <% if posts.any? %>
2: <div id="posts">
3: <% posts.each do |post| %>
4: <%= render partial: "posts/post", locals: { post: post } %>
Changing the problem line to
<%= render #posts %>
made the error disappear and the posts appear (displayed nicely in markup from the appropriate partials) as I had wanted and expected them to.
Here's my _posts.html.erb partial:
<% if posts.any? %>
<div id="posts">
<% posts.each do |post| %>
<%= render partial: "posts/post", locals: { post: post } %>
<% # render :partial => "comments/comments", :collection => post.comments %>
<% end %>
</div>
<% end %>
And the _post.html.erb partial it's referring to, if that matters:
<div class="post" id="post_<%= "#{post.id}" %>">
<div class="post_inner">
<%= link_to avatar_for(post.user, size: "small"), post.user.profile %>
<div class="post_body">
<div class="user-tools">
<% if can? :destroy, post %>
<%= link_to '<i class="fi-x"></i>'.html_safe, post, :method => :delete, remote: true, :class => "delete", :confirm => "Are you sure you want to delete this post?", :title => post.content %>
<% end %>
</div>
<h5 class="username">
<%= link_to post.user.name, post.user.profile %>
<span class="timestamp">• <%= time_ago_in_words(post.created_at) %> ago</span>
</h5>
<div class="content">
<%= post.content %>
</div>
<ul class="foot">
<li>Like<li>
<li>Share</li>
</ul>
</div>
</div>
</div>
And the relevant bits from the controller:
class PostsController < ApplicationController
respond_to :html, :js # Allow for AJAX requests as well as HTML ones.
before_filter :load_postable
load_and_authorize_resource
def index
#post = Post.new
#posts = #postable.posts
end
private #################
def load_postable
klass = [User, Event].detect { |c| params["#{c.name.underscore}_id"] } # Look for which one of these there's a ***_id parameter name for
#postable = klass.find(params["#{klass.name.underscore}_id"]) # Call find on that, passing in that parameter. eg Event.find(1)
end
Can anyone explain to me what's going on here? I couldn't find anything in the Layouts and Rendering guide at rubyonrails.org.
Thanks!
Your error comes from assuming :collection and #posts mean the same thing when rendering. From Rails Docs (point 3.4.5):
Partials are very useful in rendering collections. When you pass a collection to a partial via the :collection option, the partial will be inserted once for each member in the collection
So, if you use that, for each post, you will be doing post.any? which fails as any? isn't defined for a single post.
From the same docs, you should check if render returns Nil to see if the collection is empty:
<h1>Posts</h1>
<%= render(#posts) || "There are no posts." %>
PD: Use the partial to render only one post, not all of them.
GL & HF.