Create an application that lets users submit blog ideas and allows others to upvote or downvote them.
Resources: NeetoUI
Things you need to know: Box-shadow, Background Color, Gradient Styling, Browser Events, DOM Manipulation, Form Validation, Modal Display.
Create an application that lets users submit blog ideas and allows others to upvote or downvote them.
Resources: NeetoUI
Things you need to know: Box-shadow, Background Color, Gradient Styling, Browser Events, DOM Manipulation, Form Validation, Modal Display.
To begin, generate a new Rails app, named blog-it
, with the configurations outlined in the preceding chapters.
Afterwards, create a Post
model with the following attributes:
title
: This field indicates the title of the idea post for a blog and should not be NULL.
description
: This field indicates the content of the post. It should not be NULL.
upvotes
: This integer field indicates the number of upvotes for the post. It should have a default value of zero and should not be NULL.
downvotes
: This integer field indicates the number of downvotes for the post. It should have a default value of zero and should not be NULL.
is_bloggable
: This boolean field indicates whether the idea can be transformed into a blog. It should have a default value of false.
Add the following validations to the Post model:
Validate the presence of the title field. Also, make sure that it has a maximum length of 125 characters.
Validate the presence of the description field. Also, make sure that it has a maximum length of 10000 characters.
Validate the presence of the is_bloggable field. If you want to validate the presence of a boolean field, you will want to use validates_inclusion_of :field_name, in: [true, false]
.
Now, open up the Rails console to experiment with the validations
Create a post with an empty title. Ensure that the entry is invalid.
Create a post with a title exceeding the maximum character limit. Ensure that the entry is invalid.
Create a post with valid values and ensure no unexpected errors are thrown.
At this point, you should have a Post
model and corresponding validations. Now add a posts controller with index
action to list all the posts.
Integrate React to your Rails app as outlined in the preceding chapters.
Create a Navbar
/Sidebar
component that displays navigation items such as Blog Posts
and other upcoming navigation items.
You can design a suitable UI in React to display the list of posts. A sample UI is provided below. Each post should be represented as a card component. Each card should display the title, a preview of the description, and the date it was created. If the preview exceeds two lines, it is recommended to truncate the excess description using an ellipsis to ensure a cleaner and more concise display.
You can depend on NeetoUI given in the resources for assistance, as developing custom components from scratch can be a laborious and time-consuming process.
Incorporate slugs for each of your posts, as learned in the preceding chapters, similar to the implementation in the Granite application.
Add frontend and backend capabilities to create a new post. The post creation form should allow users to submit the title and description of a potential blog idea.
Add a new item in the Navbar, as well as an Add new blog post
button on the listing page, to navigate to the page for creating a new blog post.
Once a user submits the form, the application should redirect to the post listing page and display the newly added blog post.
When a user clicks on the post title from the listing page, they should be redirected to another page displaying the post's title and detailed description. The route of this page should be based on the slug of the post.
Create an Organization
model with a name
attribute. Migrate the database and add an entry for a sample organization through the Rails console.
Add a User
model with attributes name
, email
and password_digest
. It is recommended that candidates utilize the bcrypt
gem for secure password hashing. Additionally, include a foreign key referencing the Organization
model within the User
model. So, every user should belong to an organization.
In the Organization
model, the name
attribute should not be NULL. In the User
model, proper validations for name
, email
, password
and password_confirmation
should be added.
Create a Category model with a name
attribute. Each post can be associated with more than one category.
Modify the Post
model by adding foreign keys that reference both the User
and Organization
models. Additionally, the Post
model should have an association with the Category
model to allow each post to be linked to multiple categories. This will ensure that each post has an author, is associated with an organization, and can have various categories.
Modify the post listing page to display the name of the author and the categories associated with each post card.
Add a searchable select input for enabling the user to select the categories for the blog post.
Add an item in the NavBar
to show the list of categories. Upon clicking this item, an additional sidebar should open, listing the categories. The sidebar should include an option to search for categories and to add new categories. When a category is clicked, only the posts with that particular category should be displayed. If no category is clicked, all posts should be displayed.
Include the author's name and categories on the blog post page.
Implement the Sign-up, Login, and Logout functionalities similar to what we had in the Granite application. Please ensure that the post listing page displays only the posts created by authors who belong to the same organization as the currently logged-in user.
Add the necessary tests for your models and controllers. Make sure your application is thoroughly tested. To ensure thorough testing, it is imperative to maintain a test coverage of 100% for all model and controller codes.
Add a post edit page for updating existing posts.
Make modifications to the New blog post
page and add a new header. In this header, an action dropdown should enable the user to either save the post as a draft using the Save as draft
option or publish it using the Publish
option. The same functionality must be present on the Edit blog post
page. Additionally on the Edit blog post
page, a horizontal menubar icon at the top right corner must be present to enable the user to delete the post in question.
Ensure that the user can edit their own blog post, from the view of blog post page. Also, change the date displayed on the blog post page to show the last published date instead of the creation date.
Add a table in My blog posts
page with the following columns:
The title
column houses the title of the post. If the title is too long it should be truncated and suffixed with an ellipsis. You can use a tooltip to display the expanded title when it is in the truncated form. The title should be a link to the edit page for that post.
The category
column with the categories of the post.
The last published at
column contains the date and time at which the post was last published. You should note that this column can have a valid value even when the post has a draft status.
The status
column indicates the status of the post and can take two values: Draft
and Published
. Note that the status should be capitalized.
The horizontal menu icon should be a dropdown with two items, that dynamically change with the status of the post.
If the post is in draft
state, then Publish
 and Delete
 options should be available via dropdown. If the post is in a published
state, then Unpublish
and Delete
 options should be available via dropdown.
Add a preview button for viewing blog post.
If the blog post is in a draft state, have a tag next to the title to indicate the same.
Add a column filter which is accessed through the action dropdown present at the top right corner of the My blog posts
page with the label Columns
. When the action dropdown is clicked, it should display a list of checkboxes that gives the user control over which columns to be displayed. By default, all the checkboxes must be checked. The user should NOT be able to uncheck the title
column.
Add a button for search filters next to the column filter action dropdown. When the button is clicked, a search filters pane should open, allowing the user to filter based on title, category, and status. Once the filters are applied, the selected criteria should be reflected in the filter query as well.
Make usage of service objects while filtering in backend.
Add ability to select specific rows using the checkbox adjacent to it. It must be noted clicking the checkbox adjacent to the column name should select all rows automatically. Once the posts are selected, part of the header that enables column filtering would be replaced with the bulk actions. Add the following bulk actions:
Change status: This bulk action enables the user to change the status of the selected posts to a specified one. This can be implemented using a dropdown. Suppose a user tries to change the status of certain posts from Draft
to Published
. If one of the posts selected is already in the Published
state, then after performing the bulk action, the last published date
of that post should not change. In other terms, a published post should not be published again.
Delete: This bulk action enables the user to delete the selected posts. Before deletion, proper warnings should be given to the user.
Modify the blog post card component to feature an upvote button, a downvote button and a net vote count. The net vote count should have a value of upvotes - downvotes
and must dynamically change when a user clicks on the upvote or downvote button. Make sure the upvotes and downvotes values change on the Rails' side as well.
Each user should be restricted to only one vote.
Implement the necessary logic to toggle the is_bloggable
field in the posts table to true
when the net vote count exceeds a defined threshold. If the net vote count falls short of this threshold, please ensure that the is_bloggable
field is set back to false
. To define the constant threshold value, you may use the Rails initializers. If the implementation of this logic ought to be done via some side effects, then you may prefer to opt-in for Active Record callbacks.
When the is_bloggable
field is assigned a value of true
, a tag Blog it
must be displayed on the front-end side. For example, if the threshold is set to 40 and the net vote becomes 41, then the tag should be shown as in the figure below.
These are some of the projects you'll build while learning.