SWorD is a prototype social network realized for the "Linguaggi e Ambienti Multimediali" course at Politecnico di Torino (academic year 2012/2013). It is mostly based on the Ruby on Rails Tutorial book by Michael Hartl.
- Creation of static pages for our social network: home, about and contact
rails generate controller Pages home about contact(or from the RubyMine menu Tools > Run Rails Generator...)
- Add title to HTML files: "SWorD | Page name"
- by using the
providemethod in each view, i.e.,<% provide :title, 'Page name' %> - by editing the title tag in
app/views/layouts/application.html.erb, i.e.,<title>SWorD | <%= yield(:title) %> - learn more about
provideat http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#method-i-provide
- Add an helper to avoid wrong rendering if the page title is not declared
- in
app/helpers/application_helper.rb - by editing the title tag in
app/views/layouts/application.html.erb
-
Fill with some contents all the views
-
Add
bootstrap-sassgem to include the Bootstrap framework with Sass support http://twitter.github.io/bootstrap/
- update the
Gemfile - run
bundle install
- Add and fill a custom SCSS file in
app/assets/stylesheets
-
Move HTML shim, header and footer code in three partials (placed in
app/views/layouts/) -
Update the
routes.rbfile, according to the table present in the exercise 1 text -
Update links present in
_header.html.erband_footer.html.erb -
Add a faq page:
- add a new view called
faq.html.erbwith a content similar to the other views - update the Pages controller
- add the corresponding named route to
routes.rb
- Add a Users controller and a page named "new"
rails generate controller Users new(or from the RubyMine menu Tools > Run Rails Generator...)- fill the content of the
new.html.erbview - update/add the corresponding named route to
routes.rb, mapping it with the signup URI - update the "Sign Up" link present in
home.html.erb
- Generate the User model, with two attributes: name and email
rails generate model User name:string email:string(or from the RubyMine menu Tools > Run Rails Generator...)
- Migrate the model to the database (i.e., create the table and columns corresponding to the User model)
bundle exec rake db:migrate(or from the RubyMine menu Tools > Run Rake Tasks...)
- Add some gems to the Gemfile (and perform a
bundle install)
annotate(version 2.5.0) to show some annotations in the Rails modelsbcrypt-ruby(already present, but commented) to have some state-of-the-art hash functions available in Rails
- Annotate the User model to show a little bit more information
bundle exec annotate(or add a new configuration of type Gem Command from the RubyMine menu Run > Edit Configurations...)
-
Add debug information in
application.html.erb, by using thedebugmethod -
Add some validations to the User model
namemust be always present (presence: true) and it must have a maximum length of 50 characters (length: { maximum: 50 })emailmust be always present, unique (uniqueness: { case_sensitive: false }) and with a specific defined format (format: { with: VALID_EMAIL_REGEX })
- Enforce the uniqueness of the email by using a migration
- add an index on the
emailcolumn in the database
- Give to the User model a
passwordfield
- generate/migrate a migration to add a column to store the password digest (i.e., an encrypted version of the password)
- update the User model with two virtual attributes:
passwordandpassword_confirmation - add the
has_secure_passwordmethod to the User model, to use the authentication system of Rails
- Add routes for users
resources :usersinconfig/routes.rb
-
Add a user in the database, by editing the action
newin the Users controller -
Add a new view associated to the Users controller
- create
show.html.erbinapp/views/users(filled with some contents) - update the page stylesheet
- add the corresponding action to the User controller (
users_controller.rb)
- Add an helper for using a Gravatar as profile pic for the users (in
users_helper.rb)
- update the view responsible of showing users (
show.html.erb)
-
Complete the Gravatar helper
-
Remove the existing user
- in the database:
bundle exec rake db:reset(or from the RubyMine menu Tools > Run Rake Tasks...) - in the code: delete the lines in the
newaction of the Users controller
- Add the sign up form in the
new.html.erbview
- by using the
form_forhelper method, which takes in an Active Record object and constructs a form using the object’s attributes - by adding
@user = User.newto the corresponding action in the Users controller
-
Update the stylesheet for a better rendering of the form
-
Add the
createaction needed to the sign up form to the Users controller
- create a new User with the information inserted in the form
- if it is possible to save such a user into the database, go to the user profile page
- otherwise, go back to the sign up form
- Update the sign up form to show error messages (if any)
- add a _error_messages.html.erb partial (in views/shared) to store the code for showing error messages of a generic form
- update the stylesheet
- Add the flash to welcome newly registered users to our site
- insert an area to show the flash message in application.html.erb
- fill the flash if the user signup has been successful (i.e., in the Users controller)
- Include the SessionHelper to the ApplicationController (helpers are automatically added to views, but not to controllers) and create the corresponding helper
- add
include SessionsHelperinapp/controllers/application_controller.rb - define a method named
handle_unverified_requestto prevent cross-site request forgery attacks inapplication_controller.rb - create
sessions_helper.rbinapp/helpers
- Add a migration to associate a user to its remember token (to be added in the traditional Rails session)
- generate/migrate a migration to add a column and a index for the remember token
- Update the User model to handle the remember token
- add a callback method to create the remember token (
before_save :create_remember_token); Rails will look for acreate_remember_tokenmethod and run it before saving the user - define such method as private and generate the token by using the
SecureRandom.urlsafe_base64function to generate a random string, safe for use in URIs, of length 16
-
Define the
sign_inmethod in theSessionsHelper -
Define two methods to set and get the current (logged) user for passing this information to all the other pages in the
SessionsHelper -
Define a
is_signed_in?method in theSessionsHelper -
Define a sign out method in the
SessionsHelper
-
Generate a Sessions controller
-
Update routes to implement the session as a RESTful resource
- add
match '/signin', to: 'sessions#new'andmatch '/signout, to: 'sessions#destroy', via: :delete - add
resources :sessions, only: [:new, :create, :destroy]
-
Fill the Sessions controller with the required actions (new, create and destroy)
-
Create the view for the signin form (i.e.,
app/views/sessions/new.html.erb)
- we need to ask for email (the username in our social network) and password
- since a session is not a Model, define the form as
form_for(:session, url:session_path), where the former element is the resource name and the latter is the corresponding URL - submit the form will result in
params[:session][:email]andparams[:session][:password]to be used in thecreateaction
- Write the
createaction in the Sessions controller
- get the registered user starting from the email given in the sign in form (
params[:session][:email]) - check if the user exist and if the given password is correct (
if user && user.authenticate(params[:session][:password])) - handle a successful login (call the
sign_inmethod declared in theSessionsHelper) - handle a failed login (show an error message and go back to the login form)
-
Update the links in the header
-
Add the Boostrap javascript library to
application.js -
Update the sign up method to perform a login if the registration was successful
-
Write the
destroyaction in the Sessions controller for signing out
- call the
sign outmethod of SessionsHelper - redirect to the homepage
- Create the
editaction and view for the Users
- please note that the
editview is almost identical to thenewview
-
Update the Settings link in the header
-
Define the
updateaction in the Users controller
- it is the action called after the edit form submission
- get the updated user information from the edit form (
params[:user]) - check if the update was successful and handle the success and fail cases
- Since, right now, everyone can edit user information, implement some controls
- add a filter to the Users controller: before performing the edit and update actions present in the controller, check if the user is signed in (
before_filter :signed_in_user, only: [:edit, :update] - add a filter to the Users controller: before performing the edit and update actions present in the controller, check if the current user is the correct user (
before_filter :correct_user, only: [:edit, :update]) - add the two methods declared in the before filters in the Users controller
- add another helper method to the SessionsHelper: check if the user for which the editing actions are called is also the current user
- Add the
indexaction and view
- the action must be called only for signed in users: add
indexto the firstbefore_filterin the Users controller - in the view, cycle upon all the users
- update the
gravatar_forhelper to show different image sizes - add some custom SCSS to
custom.css.scss - update the corresponding link in the header
- Generate some sample users
- add the
fakergem to the project - perform a
bundle install - write a rake task (in
lib/tasks/sample_data.rake) for generating 100 users - clean the database content (
bundle exec rake db:reset, or from the RubyMine menu Tools > Run Rake Tasks...) - execute the newly created task (
bundle exec rake db:populate, or from the RubyMine menu Tools > Run Rake Tasks...)
- Add pagination to the
indexview and action
- add the
will_paginateand thebootstrap-will_paginategems - perform a
bundle install - edit the
indexview to include thewill_paginatemethod (it shows the link to the next and previous pages) - edit the
indexaction to properly prepare data for the correspective view (by using thepaginatemethod in retrieving users)
- Add the admin user
- generate a new migration to add the admin column in the database (with a boolean value):
add_admin_to_users - update the newly generated migration to set the admin field to false, by default
- migrate!
- update the
sample_data.raketask to assign admin privilegies to the first user - clean the database content (
bundle exec rake db:reset, or from the RubyMine menu Tools > Run Rake Tasks...) - execute the updated task (
bundle exec rake db:populate, or from the RubyMine menu Tools > Run Rake Tasks...)
- Let the admin delete other users
- edit the
indexview to add a delete link near each user - add the
destroyaction in the Users controller - update the
signed_in_userfilter to include thedestroyaction - add a before filter named
admin_userto ensure that only admin can delete users
- Create the Post model, with two attributes: content and user_id
rails generate model Post content:string user_id:integer(or from the RubyMine menu Tools > Run Rails Generator...)- in the migration, add an index to help retrieve all the posts associated to a given user in reverse order of creation
- migrate such updates to the database
- Update the Post model
- by removing
user_idfrom the accessible attributes - by validating the presence of
user_id - by validating the presence and the length of
content
- Link posts with users
- add
belongs_to :userto the Post model - add
has_many :poststo the User model - set a descending order (newest to oldest) from post, add
default_scope order: 'posts.created_at DESCto the Post model - if a user is destroyed, all her posts must be also destroyed: update the relationship between users and posts in the User model
- Show the posts in the user home page
- update
show.html.erbbetween the Users view - add a partial (
app/view/posts/_posts.html.erb) for showing a single post - edit the
showaction in the Users controller to correctly handle the updated view
-
Create some fake posts by editing the
sample_data.raketask -
Add some custom SCSS
-
Add the
createanddestroyroute for the Posts resource inroutes.rb
- we show posts through the Users controller, so we don't need any other route
-
Create an (empty) Posts controller
-
Only signed in users can create or delete a post
- move the
signed_in_usermethod to theSessionHelper - add a
before_filterto the Posts controller
- Add code for creating a new post
- add a
createaction in the Posts controller to build and save a post - update the homepage to show different content whether a user is logged in
- add a form for the creation of a new post in the homepage (
home.html.erb) and update the corresponding action in the Pages controller - update the
error_messagespartial to handle errors coming from various objects, not only User
- Add code for deleting an existing post (each user can delete only her own posts)
- add a
destroyaction in the Posts controller to delete a post - add a link for deleting a post in the
postpartial (inapp/views/posts), similar to the one used for deleting a user - add a
before_filterin the Posts controller to check if the user is allowed to delete the desired post (correct_user) - define the
correct_userprivate method in the Post controller
- Generate a Relationship model for followers and followed users
rails generate model Relationship follower_id:integer followed_id:integer(or from the RubyMine menu Tools > Run Rails Generator...)- add three indexes on
follower_idandfollowed_id(by acting on the migration) - remove
follower_idfrom the list of accessible attributes of the model - migrate the whole
- Build the User/Relationship association
- a user has many relationships: update the User model
- a relationship belongs to a follower and a followed user: update the Relationship model
-
Add some validations on the two attributes of the Relationship model
-
Update the User model to include Followed user properties
- a user has many followed user, through the relationships table
- define some useful methods (is the current user following a given user? follow and unfollow a user)
- Update the User model to include Followers properties
- a user has many "reverse" relationships
- a user has many followers through the previously defined "reverse" relationships table
- Add some sample following data by updating the
populaterake task
- reset the database, and populate it again
-
Add routes for following and follower
-
Add some user statistics (e.g., number of followers and followed users)
- create the
_stats.html.erbpartial in thesharedfolder - include the partial in the home page and in the user profile
- update the stylesheet
- Add the follow/unfollow button (form)
- create the a general
_follow_form.html.erbpartial in theview/usersfolder - add a route for handling relationships
- create the
_follow.html.erbpartial in theview/usersfolder - create the
_unfollow.html.erbpartial in theview/usersfolder - render the
_follow_form.html.erbpartial in the user profile
- Add pages for listing followers and followed users
- add two new actions in the User controller for following and follower (based on previous routes)
- add
show_follow.html.erbin theview/usersfolder - add a
_user.html.erbpartial in theview/usersfolder to avoid code replication
- Add the
createanddestroyaction in the Relationship controller
- create the Relationship controller
- Add some ajax to the follow/unfollow button
- edit the
_follow.html.erband_unfollow.html.erbpartials to support javascript - update the Relationship controller to reload the destination page by using ajax
- create the javascript files corresponding to the two actions in
view/relationships
- Implement the status feed (i.e., the wall)
- we want to show, in the home page for a signed in user, her posts and posts from their followed users
- update the User model by defining a
feedmethod to get these posts - update the Post model to implement the method called by the User model for the wall
- add the status feed in the home page view/action
- update the
createaction in the Post controller to prepare a data structure for properly show the feed items
-
Add a route to support simple user search, by editing
routes.rb(to matchusers/search) -
Create a partial in the users views for the search form
- render the search form in the header, only for signed in users
- Implement the
searchaction in the Users controller
- add the corresponding search method in the User model (
self.searchsince it is a class method) - add a
searchview for showing found users (in/view/users/)
-
Add and install the simple-private-messages gem to the Gemfile
-
Create the private message model by running the
simple_private_messages:model generator
rails generate simple_private_messages:model User Message(or from the RubyMine menu Tools > Run Rails Generator...)- the previous operation generate a Message model and link it to the user model already present in the app (User, in our case)
-
Migrate the generated migration to create a
messagestable -
Update the User model to use the newly created messages, by adding
has_private_messages -
Update the routes
- add a resource to create and destroy user's messages
- update the user resource to handle messages
-
Add
createanddestroyactions to the Message controller -
Update the User show view to include a "New message" button (currently it is a link, but it could also be a form like the follow one)
- when clicked, call the
newaction in the Messages controller - it will show a modal window to compose a new message
- Update the User statistics (
statspartial) to show received messages
- each user can see their own messages, only
- Add to the User controller a
messagesaction to show all the user's message
- create the corresponding view
-
Update the
newaction in the Message controller to compose reply messages -
Update the
populaterake task to generate some fake messages