Click here to load reader
Upload
sagar-arlekar
View
1.504
Download
0
Embed Size (px)
DESCRIPTION
'Linux For You' article by http://foodlets.in founders Govind Naroji and Sagar Arlekar. This is a tutorial on will_paginate (pagination), authlogic + omniauth (authentication) and paperclip (file attachments) plugins.
Citation preview
Aplug-in is a wonderful way to package a frequently implemented solution to a common problem and reuse the code. In case you had to build a blogging
application, you could use a blog plug-in, an authentication plug-in, an image-upload plug-in, a comments plug-in and a ratings plug-in. Plug-ins make it super simple to create an application, and save a lot of effort, which in turn, allows you to focus on the user interaction, security and testing.
In this article, we will discuss some of the plug-ins that made our life easy while building Foodlets.in, a visual guide for restaurant food.
For the purpose of this article, let's build a basic events-management application on Rails version 2.3.8. This app would have the Event and the User models. We shall add in features like user authentication, Facebook Connect, pagination for listing events, image attachment and the ability to use jQuery in place of the default libraries. For your
reference, we have made the source code of this app available on GitHub: https://github.com/gnaroji/Events-Application.
To create a new Rails app, issue the following command:
rails events
cd events
Let's use a scaffold to get started:
script/generate scaffold Event title:string description:string
start_date:date end_date:date user_id:integer
And here’s another scaffold for the User model:
script/generate scaffold user login:string email:string
persistence_token:string crypted_password:string password_
salt:string
This article is a tutorial on how to use Rails plug-ins for pagination, authentication and file attachments. It is aimed at readers with a basic knowledge of Ruby on Rails programming.
Rails Plug-insMaking site Development Easy!
www.LinuxForU.com | LINUX For YoU | March 2011 | 69
Developers Tutor ia l
Paperclip plug-inThis plug-in adds an image to the event, and shows a thumbnail. It helps in handling file attachments and their storage on the server’s file-system. It allows uploaded files to be handled like regular model fields/properties. It also includes methods to validate file size, file type, etc. Paperclip proves to be excellent while handling image attachments. It uses Imagemagick to resize images and generate thumbnails.
InstallationInstall the plugin from the online git repository:
script/plugin install https://github.com/thoughtbot/paperclip.git
This will install the paperclip plugin under events/vendor/plugins
UsageLet us add an image attachment to our Event model:
script/generate paperclip event image
Paperclip comes with a generator, and this command will create a migration named TIMESTAMP_add_attachments_image_to_event.rb in the events/db/migrate/ directory. This migration will add the following fields to the Event model:
• image_file_name• image_content_type• image_file_size• image_updated_atRun the migration, as follows:
rake db:migrate
We need to specify in the Event model that it uses an image attachment. The code to be added to the model is:
# events/app/models/event.rb
has_attached_file :image,
:styles => {:thumbnail => "100x100#", :large => "500x500#"}
The styles parameter mentions that we need a thumbnail of size 100*100 pixels, and a large image of size 500*500 pixels. ‘thumbnail’ and ‘large’ are labels, and could be words of the user’s choice. Let's add in a few validations:
# events/app/models/event.rb
validates_attachment_size :image, :less_than => 5.megabytes,
:message => "Image should be present and less than 5
MB in size"
validates_attachment_content_type :image,
:content_type => ['image/jpeg','image/png','image/
jpg'],
:message => "Attachment should be a jpg, jpeg or a
png"
The first validation will verify that the image size is less than 5 MB, and the second will verify that only JPEG and PNG images are stored.
Changes to viewsTo facilitate the upload of the image, we need to make the ‘new event’ and ‘edit event’ forms multi-part. Replace the following code…
# events/app/views/events/new.html.erb and events/app/views/
events/edit.html.erb
<% form_for(@event) do |f| %>
…with:
# events/app/views/events/new.html.erb and events/app/views/
events/edit.html.erb
<% form_for(@event, :html => { :multipart => true } ) do |f| %>
Then add the file field given below:
# events/app/views/events/new.html.erb and events/app/views/
events/edit.html.erb
<%= f.file_field :image %>
To display the image thumbnail in the show and index views, you should add the following helper:
# events/app/views/events/show.html.erb and events/app/views/
events/index.html.erb
<%= image_tag @event.image.url(:thumbnail) %>
To learn more, check https://github.com/thoughtbot/paperclip/wiki.
Will_Paginate plug-inThis plug-in will allow us to implement pagination, i.e., to break a long list of data items into numbered pages. We shall restrict listings to five events per page in the Event index view.
InstallationInstall will_paginate from the online git repository:
script/plugin install git://github.com/mislav/will_paginate.git
This will install the will_paginate plugin under events/vendor/plugins
UsageIn the index method of EventsController (events/app/controllers/events_controller.rb), replace the following code…
70 | March 2011 | LINUX For YoU | www.LinuxForU.com
Developers Tutor ia l
@events = Event.all
…with:
@events = Event.paginate(:per_page => 5, :page => params[:page],
:order => 'updated_at DESC')
Here, the parameters are as follows:• :per_page: number of records on a page.• :page: the number of the page to be fetched; the
default is 1.• :order: to decide on the ascending or descending order
on a field.Other parameters like :conditions, :include, etc, can also
be used. For example, to list all events starting today, or in the future, you could add in a condition:
@events = Event.paginate(:per_page => 5, :page => params[:page],
:order => 'DATE(start_date) asc', :conditions => ['start_date >=
?', Date.today])
In the index view, add the following code wherever you want the pagination links to appear:
# events/app/views/events/index.html.erb
<%= will_paginate %>
For further reading, check http://rubydoc.info/gems/will_paginate/.
Authlogic plug-inAuthlogic is an easy-to-use but powerful authentication plug-in for Rails. In laymen terms, it gives you user registration, sign-in (with a ‘Remember me’ option), sign-out and user account activation. Our rule is that only authenticated users can create an event.
InstallationRun the command to install the plugin:
script/plugin install git://github.com/binarylogic/authlogic.git
Adding user authentication to the applicationThe first thing that you need to do is associate the authentication functionality with the User model:
#user.rb
acts_as_authentic do |c|
c.require_password_confirmation = false
end
In this tutorial, we are going to focus on user authentication only, and will create a new user using the create operation provided by the scaffold. We need to make
one change to the view for new user -- the form should capture only email, login and password fields. Now, you must have noticed that our User model doesn’t have a password field, so how can we use it in the new form? That's because the password is encrypted before it is stored—Authlogic takes the value of your password, encrypts it and stores it in the crypted_password field.
Once you associate a model with Authlogic, by default it adds a set of validations for the fields. Most of the fields are optional, but password confirmation is required by default; if you don’t need it, then set it to false. You can read more about the other fields at the Authlogic ActsAsAuthentic documentation.
Create the UserSession model:
script/generate session user_session
Now create the UserSessionsController. Remember that the sign-in will not require the user to be signed in, while sign-out can happen only if the user is already signed in.
# events/app/controllers/user_sessions_controller.rb
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => :destroy
Add the following code to the new and create methods for the sign-in:
# events/app/controllers/user_sessions_controller.rb
# new
@user_session = UserSession.new
# create
@user_session = UserSession.new(params[:user_session])
if @user_session.save
flash[:notice] = "You have signed in successfully!"
redirect_to root_url
else
render :action => :new
end
For the sign-out, simply destroy the user session:
# app/controllers/user_sessions_controller.rb
# destroy
current_user_session.destroy
flash[:notice] = "You have signed out successfully!"
redirect_to root_url
In the view for the sign-in, the form should look like what follows:
# app/views/user_sessions/new.html.erb
<% form_for @user_session, :url => user_session_path do |f| %>
www.LinuxForU.com | LINUX For YoU | March 2011 | 71
Developers Tutor ia l
# fields for username, password, remember_me
<% end %>
Next, wire up the routes:
# config/routes.rb
map.resource :user_session
map.root :controller => "events_controller", :action => "index"
You then need to add some code to the Application Controller for persisting the session.
Declare the helper methods current_user_session and current_user, which can be used in other controllers where the session object or the current user object is required:
# app/controllers/application.rb
helper_method :current_user_session, :current_user
We don’t want the password to be written to the log files!
# app/controllers/application.rb
filter_parameter_logging :password
Besides the helper methods, you need to add two authentication methods to the Application Controller:
• require_user: to be used in controller actions that require signed-in users
• require_no_user: to be used in controller actions that require non-signed-in users
# app/controllers/application.rb
# current_user_session (for retrieving the current session)
return @current_user_session if defined?(@current_user_
session)
@current_user_session = UserSession.find
# current_user (for retrieving the current user)
return @current_user if defined?(@current_user)
@current_user = current_user_session && current_user_
session.user
# require_user
unless current_user
flash[:notice] = "Please sign in to access this page"
redirect_to root_url
return false
end
# require_no_user
# check if it is the current_user
That’s it! You are ready to use authentication in the application now! Next, ensure that only signed-in users can
create new events. Add the following code to the start of the new method in the Events Controller:
# events/app/controllers/events_controller.rb
# new
if current_user.nil?
flash[:notice] = "You must be logged in to access this page"
redirect_to (new_user_session_url)
return
end
Try to create a new event without signing in—it should take you to the sign-in page, /user_sessions/new. For sign-out, use: /user_sessions/destroy.
Read more about Authlogic at https://github.com/binarylogic/authlogic.
Omniauth plug-inOmniauth is a Rails plug-in that enables external authentication for your application. It allows people to use Facebook Connect. Some other supported external providers are Twitter and Foursquare via OAuth, Google Apps via OpenID and Flickr.
InstallationInstall the plugin from the repository at github:
script/plugin install git://github.com/intridea/omniauth.git
Adding Facebook authentication to the Events applicationFor Rails v2.3.8, you need to create an initialiser for Omniauth, and specify a strategy for each external provider:
# events/config/initializers/omniauth.rb
ActionController::Dispatcher.middleware.use
OmniAuth::Strategies::Facebook, '<APP_ID>', '<APP_SECRET>'
Please note that you have to register your app with Facebook in order to get the API key. Also, you need to ensure that you provided the correct settings for your Facebook App:
Site URL = http://yoursitename.com
Site Domain = yoursitename.com
Next, add a ‘Connect with Facebook’ button to the home page (you can get the Facebook button image from the Facebook Developers website):
# app/views/events/index.html.rb
<a href="/auth/facebook"><img src="/images/fb-small-button.png"
alt="Connect with Facebook"/></a>
72 | March 2011 | LINUX For YoU | www.LinuxForU.com
Developers Tutor ia l
This link takes you to ‘/auth/facebook’ as required by Omniauth, after which Omniauth redirects you to Facebook, which then takes care of authenticating you, and returns a response message on the callback URL /auth/facebook/callback. This callback URL needs to be configured in routes for all providers:
# events/config/routes.rb
map.connect '/auth/:provider/callback', :controller => 'user_
sessions', :action => 'social_session_create'
The response that you get from Facebook is an OAuth response, and will contain a UID field which denotes the user’s unique OAuth ID at Facebook and a provider field (set to facebook), besides other fields like name, email, etc. Let’s create a new model to store the key fields, along with an additional user_id field to map it to your User model:
script/generate model authorization provider:string uid:string
user_id:integer
This will generate authorization.rb, and you need to associate it with your User model by adding a has_one association as follows:
# events/app/models/authorization.rb
has_one :user, :primary_key => "user_id", :foreign_key => "id"
For external authentication, handle the session creation differently in the UserSessionsController. Use a new method, create_social_session:
# events/app/controllers/user_sessions_controller.rb
# create_social_session
# get the auth response from the request
@auth_response = request.env['rack.auth']
# Check if the user has an existing social profile
# (in the Authorization model - match on uid,provider)
@auth = Authorization.find_from_hash(@auth_response)
# if the user doesn't have a social profile then nil is
returned
if @auth.nil?
# Create a new user or add an authorization to an existing
user
@auth = Authorization.create_from_hash(@auth_response)
end
# Log-in the authorizing user with remember me as false
@user_session = UserSession.create(@auth.user, false)
if @user_session.save
flash[:notice] = "Successfully logged in."
redirect_to root_url
else
flash[:notice] = "Login failed!"
render :action => 'new'
end
We will not discuss authorisation methods, as they are simple CRUD methods on either the Authorization model or the User model. The gist of this code is that you need to extract and process the response from Facebook.
That's it! You now have Facebook Connect for your application. Who would have thought that it could be so simple? Thanks to the people at Intridea who came up with this wonderful plug-in! Read more about Omniauth at https://github.com/intridea/omniauth.
JRails plug-inRails, by default, uses the Prototype JavaScript library. When a new Rails project is created, the following files will be present in the events/public/javascripts/ directory:
• prototype.js• effects.js• dragdrop.js• controls.jsThe last three are script.aculo.us libraries. If you wish
to use jQuery instead, don’t worry, jRails comes to the rescue. This plug-in lets you use your favourite JS library, jQuery, instead of Prototype. It includes the jQuery equivalent (jquery.js and jquery-ui.js) of the above four files in your app. jRails will allow your app to use the Rails JavaScript helpers by callingjQuery functions.
InstallationInstall the plugin from github:
script/plugin install https://github.com/aaronchi/jrails.git
UsageAdding the following helper to the view will include jquery.js and jquery-ui.js in the HTML:
# e.g. events/app/views/events/new.html.erb
<%= javascript_include_tag :defaults %>
Now you can include any jQuery library and call the functions through the available Rails helpers, or pure JavaScript code. To know more about jRails, go to https://github.com/aaronchi/jrails/wiki.
Well, the next time you think of a feature for your Rails app, just Google around, there could be an existing plug-in for it! It’ll save you a lot of time...
By: sagar arlekar and govind naroji
Sagar and Govind are the creators of Foodlets—a visual guide for restaurant food. They are open source enthusiasts. Foodlets.in has been built entirely using open source technologies. They can be reached at [email protected] and [email protected].
www.LinuxForU.com | LINUX For YoU | March 2011 | 73
Developers Tutor ia l