For our bookmarking-app we will need in the first place the bookmarks itself stored in our database. They should belong to a certain user and have a title, the address of the bookmark and a short description.
In Camping-code in the Module-Section that looks as following:
module Grabr::Models
class Link < Base
belongs_to :user
has_many :tags
end
class Tag < Base; end
class User < Base; end
class CreateTheBasics < V 1.0
def self.up
create_table :grabr_links,
:force => true do |t|
t.column :id, :integer, :null => false
t.column :user_id, :integer, :null => false
t.column :title, :string, :limit => 255
t.column :address, :string, :limit => 255
t.column :date, :datetime
t.column :description, :text
end
create_table :grabr_users,
:force => true do |t|
t.column :id, :integer, :null => false
t.column :username, :string
t.column :password, :string
end
User.create :username => 'admin',
:password => 'camping'
end
def self.down
drop_table :grabr_links
drop_table :grabr_users
end
end
end
Nothing special, I just left the tags out as we want to get running quickly and will add some additional features later.
The
:user_id connects every posted link to the user who posted it.
The next step will be the Controller. As it is quite long I'll cut it in several slices. Lets get started with the
Index-controller:
class Index < R '/'
def get
unless @state.user_id.blank?
@user = User.find @state.user_id
@links = Link.find(:all,
:conditions => {:user_id => @state.user_id})
end
render :index
end
end
When the index page is called by the url
loalhost:anyport(probably 3301)/ the Index-controller looks for a logged-in user. This is done by checking the cooky set by the Camping-server. If there is a cooky containing a valid user-id then the instance-variable
@user is created. We define another instance-variable called
@links which contain all the users bookmarked links. At the render the index page, which will use both variables which is shown in the next post.
Next block are the Add- and View-Controller:
class Add
def get
unless @state.user_id.blank?
@user = User.find @state.user_id
@link = Link.new :title => input.link_title,
:address => input.address,
:description => input.description,
:user_id => @state.user_id,
:date => Time.now
end
render :add
end
def post
unless @state.user_id.blank?
link = Link.create :title => input.link_title,
:address => input.address,
:description => input.description,
:user_id => @state.user_id,
:date => Time.now
redirect Index
end
end
end
class View < R '/view/(\d+)', '/view'
def get link_id
unless @state.user_id.blank?
@user = User.find @state.user_id
end
@link = Link.find link_id
render :view
end
def post
unless @state.user_id.blank?
@link = Link.find input.link_id
@link.update_attributes :title =>
input.link_title,
:address => input.address,
:description => input.description
redirect Index
end
end
end
The get-methods of both classes does the same user-checking as almost every other Controllers (checking user, defining some variables, rendering a page). The post-methods only differ in the way they handle the input. While the Add#post-method creates a new link in the database the View#post-method just updates the atributes. The View gets the functionality you normally put in an Edit-controller but I thought it doesn't hurt if we merge them. Something special is the fact that the Add#post-method already accepts data-input. This is used for the convenient feature of a one-click-adding feature (I'll deal with in a later post).
Next one is the Delete-method (sorry, it's kind of a marathon but 300 lines are still 300 lines):
class Delete < R '/delete/(\d+)', '/delete'
def get link_id
unless @state.user_id.blank?
@user = User.find @state.user_id
@link = Link.find link_id
render :delete
end
end
def post
unless @state.user_id.blank?
Link.delete(input.link_id)
redirect Index
else
redirect Index
end
end
end
Quite self-descriptive: the get-method does the standard-job as seen in Add/View; the post-method deletes the data-base-entry.
So just login/logout-Controllers are still missing and then we are finally finished with the controller (almost, the Styles come in the next post):
class Login
def post
@user = User.find :first,
:conditions => ['username = ? AND
password = ?',
input.username, input.password]
if @user
@login = 'login success !'
@state.user_id = @user.id
else
if input.user_add and not
input.password.empty? and not
input.username.empty?
@user = User.create :username =>
input.username,
:password => input.password
@login = 'Account successfully created!'
else
@login = 'Wrong user name or password!'
end
end
render :login
end
end
class Logout
def get
@state.user_id = nil
render :logout
end
end
The Login#get method does all the magic of logging a user in. Incase there is a new user to be created it adds an entry to the
grabr_users-table. The Login-class just sets the cooky-user-information to nil to tell Grabr the user is not longer logged in.
Puh, thats was quite a rush through the whole Grabr-controller. But I think we should quickly come to terms now, as we are all excited what Grabr looks like in action. If I'm leaving some things out or miss any point leave a hint.