Ruby on Rails: grouping blog posts by month - ruby-on-rails

Hy guys. I've created a simple blog app with the usual CRUD actions. I've also added a new action in the PostController called "archive" and an associated view. In this view I want to bring back all blog posts and group them by month, displaying them in this kind of format:
March
<ul>
<li>Hello World</li>
<li>Blah blah</li>
<li>Nothing to see here</li>
<li>Test post...</li>
</ul>
Febuary
<ul>
<li>My hangover sucks</li>
... etc ...
I can't for the life of me figure out the best way to do this. Assuming the Post model has the usual title, content, created_at etc fields, can someone help me out with the logic/code? I'm very new to RoR so please bear with me :)

group_by is a great method:
controller:
def archive
#this will return a hash in which the month names are the keys,
#and the values are arrays of the posts belonging to such months
#something like:
#{ "February" => [#<Post 0xb5c836a0>,#<Post 0xb5443a0>],
# 'March' => [#<Post 0x43443a0>] }
#posts_by_month = Posts.find(:all).group_by { |post| post.created_at.strftime("%B") }
end
view template:
<% #posts_by_month.each do |monthname, posts| %>
<%= monthname %>
<ul>
<% posts.each do |post| %>
<li><%= post.title %></li>
<% end %>
</ul>
<% end %>

#Maximiliano Guzman
Good answer! Thanks for adding value to the Rails community. I'm including my original source on How to Create a Blog Archive with Rails, just in case I butcher the author's reasoning. Based on the blog post, for new developers to Rails, I'd add a couple suggestions.
First, use Active Records Posts.all method to return the Post result set for increased speed and interoperability. The Posts.find(:all) method is known to have unforeseen issues.
Finally, along the same vein, use beginning_of_month method from the ActiveRecord core extensions. I find beginning_of_month much more readable than strftime("%B"). Of course, the choice is yours.
Below is an example of these suggestions. Please see the original blog post for further detail:
controllers/archives_controller.rb
def index
#posts = Post.all(:select => "title, id, posted_at", :order => "posted_at DESC")
#post_months = #posts.group_by { |t| t.posted_at.beginning_of_month }
end
views/archives/indext.html.erb
<div class="archives">
<h2>Blog Archive</h2>
<% #post_months.sort.reverse.each do |month, posts| %>
<h3><%=h month.strftime("%B %Y") %></h3>
<ul>
<% for post in posts %>
<li><%=h link_to post.title, post_path(post) %></li>
<% end %>
</ul>
<% end %>
</div>
Good luck and welcome to Rails!

Related

Rails - Display all questions by category

I have question and category model. Question model has category_id column.
class Question
belongs_to :category
end
class Category
has_many :questions
end
In my controller I have this:
def index
#categories = Category.all
#questions = Question.all
end
I would like to display all categories and all questions that belongs_to specified category. Also, I would like to display question numbers below each category and made links of them and later it will open new page with clicked question.
This is how I tried to do that:
<% #categories.each do |category| %>
<h1><%= category.name %></h1>
<% #questions.each do |question| %>
<ul>
<li><%= link_to question.id %></li>
</ul>
<% end %>
<% end %>
It should look like this but I get stuck:
Category1
1 2 3 4
Category2
1 2 3 4
Question: How to achieve that I display questions like is show above?
You can do it this way:
Controller:
def index
#categories = Category.all
end
View:
<% #categories.each do |category| %>
<h1><%= category.name %></h1>
<% category.questions.each do |question| %>
<ul>
<li><%= link_to question.id, question_path %></li>
</ul>
<% end %>
<% end %>
Since you said you want to display all of the categories, and the questions that belong to each of those categories, I'm assuming that the index action that you pasted in comes from your categories_controller.
One solution I can think of would be to change the instance variables inside your index. I don't really see a purpose for having the instance variable that references all of your Question objects. This is the one I'm talking about:
#questions = Question.all
Yea, get rid of that. You should be fine with just
#categories = Category.all
Since you want to display all of your categories, that instance variable is necessary. And since you mentioned you want to also display all of the questions that belong to each category, that instance variable is sufficient with the right view. You were on the right track, but instead, just use the #categories instance variable; forget about #questions. Here is what your view should probably look like (you were on the right track above):
<% #categories.each do |category| %>
<h1><%= category.name %></h1>
<% category.questions.each do |question| %>
<ul>
<li><%= link_to question.id, question_path %></li>
</ul>
<% end %>
<% end %>
Also note that in that first line of code, when you start a block, you don't need the <%= , You only need the <%. That's because that first line of the block is purely ruby in itself, it isn't actually getting printed to the resulting html.
Hope I helped a little bit!
* Also: I saw another answer on here which is missing something: When you use the <%= link_to %> helper, you need to specify the first argument which is the resulting markup (In this case you wanted the question.id) , AND ALSO A SECOND ARGUMENT, which is the path for the link to follow *

Rails - If / Else in view returning both branches

I've an 'if / else' running in my view, based on the current URL of the page, and currently the view is displaying what is should were the 'if' both true and false. It's a little tricky to explain, and I've no idea why this is happening - any explanations / solutions will be greatly appreciated!
Before the code, here's a little background:
I have recipes, each of which have one or more cuisines (via has-many-through relationships)
if the URL is, for example, /italian, I want it to display all recipes with the cuisine 'Italian'
otherwise, if the URL is invalid or doesn't have any recipes with matching cuisines, I want it to display a message stating this
(So far, so straightforward right?)
However, when the code runs, it's correctly printing the right recipes (i.e. French meals won't come up on the /italian url), BUT also printing the error message. Here's the code:
In the controller:
#url = request.path.split('/')[2] #returning 'italian', 'french', etc.
And the view:
<% Recipe.all.each do |recipe| %>
<% recipe.cuisines.each do |recipe_cuisine| %>
<% if recipe_cuisine.name.downcase == #url %>
<p><strong><%= recipe.name.humanize %></strong></p>
<ul>
<% recipe.ingredients.each do |recipe_ingredient| %>
<li><%= recipe_ingredient.name %></li>
<% end %>
</ul>
<p><%= recipe.method %></p>
<% else %>
<p>You've reached an invalid page, please return to <#%= link_to 'the homepage', root_url %></p>
<% end %>
<% end %>
<% end %>
To clarify, I've tested the 'recipe_cuisine.name.downcase == #url' line of code, and it's returning true when it should be, false when it shouldn't.
Does anyone know how to resolve this?
Thanks in advance, Steve.
Edit
Here are the routes that affect this:
Rails.application.routes.draw do
get 'recipes/:cuisine' => 'recipes#cuisine'
resources :recipes
end
You defined the following route:
get 'recipes/:cuisine' => 'recipes#cuisine'
This means when you hit /recipes, it uses the cuisine action of the recipes controller (thanks to 'recipes#cuisine').
You also defined an extra :cuisine after the recipes/, which means if you hit /recipes/italian, then you will have a GET param (named cuisine) available in your controller/view.
Here is how you can use it:
# recipes_controller.rb
def cuisine
#recipes = Recipe.all # (use `Recipe.scoped` if using Rails' version < 4)
if params[:cuisine].present?
#recipes = #recipes.includes(:cuisines).where(cuisines: { name: params[:cuisine] })
end
# other stuff
end
# cuisine.html.erb (view)
<% #recipes.each do |recipe| %>
<p><strong><%= recipe.name.humanize %></strong></p>
<ul>
<% recipe.ingredients.each do |recipe_ingredient| %>
<li><%= recipe_ingredient.name %></li>
<% end %>
</ul>
<p><%= recipe.method %></p>
<% end %>
But there is a flaw in this logic: What if I hit /recipes/frenchAndMexicanPlease ? The params[:cusine] will be equal to "frenchAndMexicanPlease", and your DB does not have any cuisine type named like this. In this case, it would display no recipe at all, since the query #recipes.includes(:cuisines).where(cuisines: { name: params[:cuisine] }) would not match any existing record.
I can obviously provide more explanations about the code and logic I used. Hope this helps!
How many cuisines are in the collection? If there are two, and one of them has a name that is equal to #url then you would see the first branch, while any that don't equal #url would show the second branch. You're evaluating that if statement for each cuisine.

Displaying tweets in my view

I'm a Rails noob and I'm following a blog post I found here...
I have everything working up until the end. Then things get nebulous.
So if I have this in my helper...
module ApplicationHelper
def display_content_with_links(tweet)
tweet.content.gsub(/(http:\/\/[a-zA-Z0-9\/\.\+\-_:?&=]+)/) {|a| "#{a}"}
end
end
Shouldn't I be able to have my tweets display in my view with this...
What am I doing wrong?
You are going to need a controller and view to have this display. Something simple like:
# app/controller/tweets_controller.rb
TweetsController < ApplicationController
def index
#tweets = Tweet.get_latest
end
end
and in the view:
# app/views/tweets/index.html.haml
%ul
- #tweets.each do |tweet|
%li
= display_content_with_links tweet
or if you use erb
# app/views/tweets/index.html.erb
<ul>
<% #tweets.each do |tweet| %>
<li>
<%= display_content_with_links tweet %>
</li>
<% end %>
</ul>
This is a pretty basic example that might not even come close to what you want, but it should point you in the right direction.
Actually, you should add
#tweet = Tweet.all
To the controller#action you have setup already, then iterate over them in your view:
<ul>
<% #tweets.each do |tweet| %>
<li><%= display_content_with_links tweet %></li>
<% end %>
</ul>

Rails - Best way / how to create Date-based Nav

I'm new to rails and am working on extending the functionality of my basic blog app. What I would like to do is create date-based navigation links. For example, I would like to have a list of links with the names of the months (as the links) and when you click on the month it shows you all the articles published in that month.
I'm struggling with how to best accomplish this.
Should I create a new Model / View / Controller for something like an ArticleArchive? Or is the solution more simple based on my needs?
I've searched the other posts in the community and none seemed to answer this. Any help with how to structure this and possibly implement is appreciated. Thanks!
Here's an example on approaching this, although in this I wanted to sort it by day. This is for your controller action:
def index
#article_days = Article.all.group_by{ |r| r.published_at }
end
To modify this to months, you'd want to do something like r.published_at.beginning_of_month in the example above and essentially group_by the name of the month.
In the view template:
<% #article_days.sort.each do |pub, articles| %>
<h3><%= pub.strftime('%e %A, %B %Y') %></h3>
<% for article in articles %>
<%= article.title %><br/>
<%= article.summary %>
<% end %>
<% end %>
There's a screencast on this as well.
UPDATE
OK - so you only want the names of the month appearing. Keep the instance variable we setup in your index action along with your other code (you probably have setup #articles = Article.all). Then where you want the links listed do:
<% #article_months.sort.each do |pub, articles| %>
<h3><%= pub.strftime('%B') %></h3>
<% for article in articles %>
<%= link_to "#{article.title}", article_path(article) %>
<% end %>
<% end %>

Adding "Featured Posts" to my blog

I am trying to add a featured post feature to my Ruby on Rails Blog. So far I have added a featured_post column to my post table and it passes a 1 if the check box is selected and 0 if not.
Now I am attempting to pull out these posts by doing the following:
/views/posts/index.html.erb
<% #featured_post.each do |post| %>
<%= post.title %>
<% end %>
And in the posts_controller.rb I am doing the following in the index action:
#featured_post = Post.all
Obviously this brings in all the post titles which is not what I want. I am assuming I have to add something to the controller to all for this but not sure what that is.
In your post model, write this
named_scope :featured,:conditions => {:featured_post => true }
write this in your controller
#featured_posts = Post.featured
and in view use this,
<% #featured_posts.each do |post| %>
<%= post.title %>
<% end %>
now you should get all the featured posts.

Resources