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." %>
Related
I've got a controller that handles articles, and recently implemented the edit and create action that way:
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render :edit, status: :unprocessable_entity
end
end
The error occours when I try to edit an article showing the message: screenshot
I'm using a form partial to load the layout this way:
<%= render "form", article: #article %>
After trying to save an new article the edit action works properly and the body error message doesn't shows if trying to save without the requirements. What should I do so solve this problem?
Thanks in advance.
There is a better way altogether to handle rendering errors - just access the object wrapped by the form builder:
<%= form_with(model: article) do |form| %>
<% if form.object.errors.any? %>
<ul>
<% form.object.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
<% end %>
# ...
<% end %>
This lets you DRY out the rendering of errors messages without having to know the name of variable which corresponds to the model instance wrapped by the form.
However you also have a classic nil error - #article is most likely nil. And this isn't an issue we can actually help you with since it cannot be reproduced if we take the code in the question at face value. Like often with stackoverflow the actual problem it lurking somewhere outside of picture.
The debug this code you need to ensure that the code you think is running is actually running and set a series of breakpoints to verify that it is indeed being set and is being passed correctly all the way to the view.
I see that you change article to #article in edit.html.erb. Because article does not exist. article exists when you render "form", article: #article use in _form.html.erb
<% #article.erors.full_messages_for(:title).each do |message|
<div><%= message %></div>
<% end %>
But i think you don't show errors in edit.html.erb
In edit.html.erb file
<%= render "form", article: #article %>
In _form.html.erb
<%= form_with(model: article) do |form| %>
<% if article.errors.any? %>
<ul>
<% article.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
<% end %>
<div>
<%= form.label :title, class: "form-control" %>
<%= form.text_field :title %>
</div>
<div>
<%= form.submit, class: "btn btn-primary" %>
</div>
<% end %>
P/S: That's my opinion, if anyone has any ideas, please leave a comment. I thank you very much
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!
I'm building a basic forum application in Ruby on Rails (v4.1.7) and I'm having an issue with displaying the topics in descending order based on their last post. The code I'm using below will show the topics in the correct descending order, however the last post times and last poster name are wrong.
When I view the topic with comments#index, these data are correct. Both comments#index and topics#index call the same partial to display the topic:
I believe this may have to do with me calling topic.comments.last
Testing it out, it seems to be displaying the FIRST comments userdata and created_at, rather than the last, however the forums ARE showing up in the correct order.
Partial: _topic.html.erb:
<article class="topic">
<h2><%= link_to(topic.title, topic_comments_path(topic)) %></h2>
<div class="author">
By <strong><%= topic.user.name %> </strong>
on <%= topic.created_at.strftime('%b %d %Y') %>
</div>
<div class="stats">
Viewed <%= pluralize(topic.view_count, 'time') %>.
<% if topic.comments.any? %>
Last comment <%= time_ago_in_words(topic.comments.last.created_at) %> ago
by <%= topic.comments.last.user.name %>.
<% else %>
No comments.
<% end %>
<span class="pull-right">
<%= pluralize(topic.comments.count, 'comment') %>.
</span>
</div>
</article>
topics_controller#index (produces incorrect data):
def index
#topics = Topic.includes(:comments).order('comments.created_at desc')
end
I have also attempted:
def index
#topics = Topic.includes(:comments).paginate(page: params[:page]).order('comments.created_at desc')
end
topics/index.html.erb(wrong data):
<% provide(:title, 'Forum Index') %>
<%= render partial: #topics, spacer_template: 'shared/hr' %>
Viewing a specific thread (in this case the topic.comments.last.user.name and topic.comments.last.created_at are the correct values):
def index
#context = context
#comments = #context.comments.paginate(page: params[:page])
end
#...
private
def context
Topic.find(params[:topic_id]) if params[:topic_id]
end
topics/index.html.erb (right data):
<% provide(:title, #context.title) %>
<h1>View Discussion</h1>
<%= render(partial: 'topics/topic', object: #context) %> # Partial with right data
<hr />
<%= render(partial: 'comment',
collection: #comments,
spacer_template: 'shared/hr',
locals: { topic: #context }) || 'No comments.' %>
<hr />
<%= render partial: 'comment_form', locals: { context: #context,
comment: #context.comments.new } %>
topic.comments.last
should be
topic.comments.first
because you're placing the latest comments first.
Where it's working fine, it is because you aren't ordering the comments and the last will fetch the comment with the highest primary index value which is most likely the ID.
Hope that clears it up.
And just FYI:
topic.comments.count
will fire up another query in your view. Change the count to size
So I have an interesting problem I'm working on. I am trying to create multiple objects of the same model in one view. I would like to display all the possible objects in my view, check boxes to select which ones to create, then submit and create all the corresponding objects.
Now the objects to select are gotten using an API request and returned in JSON format. The JSON is then displayed on the view for the user to select, then an array containing all the selected objects is sent back to the controller for creation.
Here is the relevant code that I've tried so far.
objects_controller.rb
def new
#possible_objects = <api call to get objs>
#objects = []
end
def create
params[:objects].each do |obj|
# create and save obj
end
end
objects/new.html.erb
<% form_for #objects do |f| %>
<% #possible_objects.each do |api_obj| %>
<%= check_box_tag(api_obj["name"])%>
<%= api_obj["name"] %>
<% end %>
<%= f.submit %>
<% end %>
This is definitely not the right approach, as the form will not accept an empty array as a parameter. I'm not sure where else to go with this, any pointers in the right direction would be great. Thanks.
Thanks to MrYoshiji for pointing me in the right direction, this is what ended up working
objects_controller.rb
def
#possible_objects = <api call to get objs>
end
def create
params[:objects].each do |object|
new_obj = Object_Model.new( <params> )
new_obj.save
if !new_obj.save
redirect_to <path>, alert: new_obj.errors.full_messages and return
end
end
redirect_to <path>, notice: 'Successfully created.'
end
objects/new.html.erb
<%= form_tag objects_path(method: :post) do %>
<% #possible_objects.each do |api_obj| %>
<%= check_box_tag 'objects[]', api_obj %>
<%= possible_object["name"] %>
<% end %>
<%= submit_tag 'Create'%>
<% end %>
Can you try the following?
# view
<% form_tag my_objects_path(method: :post) do |f| %>
<% #possible_objects.each do |api_obj| %>
<%= check_box_tag 'objects[names][]', api_obj["name"] %>
<%= api_obj["name"] %>
<% end %>
<%= f.submit %>
<% end %>
# controller
def create
params[:objects][:names].each do |obj_name|
YourModelForObject.create(name: obj_name)
end
end
See this comment on the documentation of check_box_tag: http://apidock.com/rails/ActionView/Helpers/FormTagHelper/check_box_tag#64-Pass-id-collections-with-check-box-tags
I have a main page that is responsible for HTML/CSS styling, but some of the contents come from partials. A partial receives some locals or params, i.e. current_user or person, and displays information if any.
Is there a way for me to check if a partial rendered anything? My end goal is something like this:
<% if my_partial can render something %>
<div class="css_for_something">
<%= render(partial: 'my_partial', locals: {...} ) %>
<% else %>
<div class="css_for_no_info">
<%= render something else %>
<% end %>
I do not want the partials to handle styling logic; they just need to display content if any. Conversely, the main page should not know anything about the logic in the partial(s), such as checking values or querying the database.
Thank you
Unfortunately, Chris Peter's solution did not work for me on rails 4.2.4, as render_to_string seems to not be available in views.
However, the following worked (rails 4.2.4):
<% partial_content = render partial: 'my_partial' %>
<% if partial_content.present? %>
<%= partial_content %>
<% else %>
<%# rendered if partial is empty %>
<% end %>
Be aware that the present? check really only checks if what was rendered is empty. If, something, e.g. a HTML comment, is returned, the check returns false.
Try storing the value generated by render_to_string in a variable:
<% partial_content = render_to_string(partial: 'my_partial', locals: {...} ).strip %>
Then you can see if it contains any content:
<% if partial_content.present? %>
<%= partial_content %>
<% else %>
<div class="css_for_no_info">
<%= render something else %>
</div>
<% end %>