Dienstag, 30. September 2008

Sessions and, or Cookies

Rails 2.0 + uses a cookie on the client bowser to store session data. Sesion data is used to protect against misuse and data theft.

If the client browser has cookies disabled the application with throw an exception for any and all PUT, UPDATE and DESTROY requests.

To safeguard this you should diable any code that results in
PUT, UPDATE and DESTROY requests if cookies are disabled in the browser client.

Just add a protected method in the application controller.

helper_method :cookies_on?
protected

def cookies_on?
..request.cookies["_appname_session"].to_s.include?('_appname_session')
end


The "_appname_session" defalts to the name for your application and is defined in the app/config/environment.rb

config.action_controller.session = {
:session_key => '_appname_session',
:secret => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}


In your controllers and views you can now write:

<% if cookies_on? %>
# show the form with the submit button
<% else %>
# show the form without the submit button and display a message telling the user that this site protects the identiy of users with coded cookies and they cannot sumbit the form without cookies enabled in the browser.
<% end %>


As the session cookie won't be avilable until the user has loaded at least two pages of your application, until then your application will be in a state of "cookies disabled".

This is all a bit of a pain, especially in the light of mobile browsers, most of which do not support cookies. However in the light of data protection, there is a real need to come up with practices to deal with this. And rails does a great job - so lets not get pissed off with rails, but more with the twits that seem to think the web is some sort of data free for all.

BTW: Setting your own cookie is as easy as
cookies [:my_name_of_cookie]="hello this string will now be in a cookie in the users browser"

The next time the user views somthing you can read the cookie:
value=cookies[:my_name_of_cookie]
puts value ->
"hello this string will now be in a cookie in the users browser"

Rake migrations effecting exisitng tables

Things that can done:

Adding a new table, Removing a table, Adding a column to an existing table, Removing a column, Renaming a column, Renaming a table, Adding an index, Adding a primary key.

>ruby script/generate migrtion add_price

This creates a new migration file in db/migrations

class AddPrice
...def self.up
.....add_column :products, :price, decimal, :precision => 8, :scale => 2, :default => 0
...end

...def self.down
......remove_column :products, :price
...end
end

Samstag, 20. September 2008

error_messages_on

BIG GOTCHA!

1. don't use redirect_to in the controller otherwise the view wont get, i.e. display the error message. user ender instead.

2. error_messages_on wants the name of the instance variable used in the controller, ie if you use,

error_messages_on 'instance_variable'

then make sure you use
@instance_variable in your controller code. Its this vairable that has the method @instance_vaiable.errors which error_on_messages uses.

Freitag, 19. September 2008

Capistrano Deployment.

Capistrano gets the latest version of the application from a given reposity and puts it online under a specific web domain.

Install Capistrano
1. install gem >gem install capistrano
2. check that worked out >cap -h

Setup app for Capistrano
1. in root directory of the application>capify

Configure Capistrano
(don't use cap deploy:cold - which is suposed to workout the configuration - you have to do the following once)
1. in app/config - edit the deploy.rb file

set :application, "nameofapp"
#Note: This will also be the name of the directory created for the app files
set :repository, "git@git.whateverthedomainis:whateverthenameis.git
#Note: This is the location of the repository of the application
set :deploy_to, "/full/path/from/server/root/directory/to/app/directory/on/server/#{application}
#Note: This is absolute location on the server where the application root directoy will be placed after being fetched from the repository
set :scm, :git
#Note: This is the resposity type (in this case a git)
set :scm_user, "name"
#Note: This is the user_name that is needed to access the repository. note: the need for a password is normally replaced by a ssh public key

set :user, "name"
#Note: This is the ssh username for the domain i.e. >ssh username@yourdomain.com

set :use_sudo, false
#Note: Capistrano will want to make some directorys on the server, it this is set to true it will use sudo before making them. I suggest to keep this false - capistrano does not need it and less things can go wrong, especially the first time.

set :branch, "whateverbranch"
#Note: The deal here is that after capistrano has cloned the repository on the server is will checkout this branch. I could not get this to work - and so expect the last version of the master branch to be checked out (at least with git and v2.5 of capistrano)

role :app, "yourdomain" # i.e. www.whatever.com
#Note: This is the address of the server that hosts the application server (i.e. mongrel, mod_rails etc)
role :web, "yourdomain" # i.e. www.whatever.com
#Note: This is the address of the server that hosts the webserver server (i.e. apache, etc)
role :db, "yourdomain" , :primary => true # i.e. www.whatever.com
#Note: This is the address of the server that hosts the database (i.e. mysql, postresql)
#Note: The :primary tells capistrano which server to run any migrations against.

Setup publickey of your server to access the application repository.
1. Login to server with a ssh shell session (i.e. >ssh name@dominnameofserver (i.e. ssh me@happy.com)) - If you are not working with public keys, then you should be asked for the password to access - after entering it you should be it.

2. cd to home on the server >cd

3. cd to the .ssh directory > cd .ssh
#Note: check for a file id_rsa.pub if its not there, then run ssh-keygen (just enter return at prompts)

3. enter on command line >more id_rsa.pub

4. Copy the key and add it to your existing repository key
Note: github.com and assembla.com have a web interface for your to do that if your repository is hosted there.

5. Check that that works by cloning the application repository by hand on the server

Freeze Rails.

>rake rails:freeze:gems

Vendorize gems #TODO.
If you are using gems but cannot install them on a sharehost then you have the option to vendorize them.

>rake gems:install
>rake gems:unpack:dependencies
>rake gems:build

Make Spin Script.
This is a small script in app/script/ called spin.rb
This script is called by capistrano after the app has been deployed to start the app and web server

#!/bin/sh

#{deploy_to}/current/script/process/spawner \
mongrel \
--environment=production \
--instances=1 \
--address=127.0.0.1 \
--port=#{port}

(#TODO Check the above)

Update Git repository.

git add .
git commit -m 'ready to deploy'
git push origin master

Deploy Setup.

git add .
git commit -m 'ready to deploy'
git push origin master


cap deploy:setup

Check Dependencies.

cap deploy:check

Deploy the Update.

cap deploy:update

Server stuff.
open a shh session on the server

>shh name@domin.xx
>cd to your app root directy
>rake RAILS_ENV=production db:schema:load
note: If this does not work - then obviously you will have to find out why and fix it before continuing.
>script/console production
note: The production environment should load up without any errors.
>>app.get("/")
note: This should return a status code of 200, 302 or similar.

Deploy Start.
On the local machine:

>cap deploy:start
note: This should return a status code of 200, 302 or similar.

Now everthing should have fired up and be working.

Dienstag, 2. September 2008

Developing Rails Plugins with RSpec

To use RSpec while developing plugins install this rspec generator plugin as follows.

Install RSpec Plugin

script/plugin install git://github.com/pat-maddox/rspec-plugin-generator.git

Create Plugin Framework
script/generate rspec_plugin new_fu


Setup Autotesting
create a file: discover.rb to vendor/plugins/new_fu/lib/autotest/


insert the following at the top of the discover.rb file:
$:.push(File.join(File.dirname(__FILE__), %w[.. .. rspec]))
Autotest.add_discovery do
rspec
end

create a spec.opts file in the plugin/new_fu/spec folder and add the following:

--colour
--format progress
--loadby mtime
--reverse

Set Plugin Location
This avoids naming conflicts with other plugins.
create a directory structure within nuw_fu/lib somthing like this.
your_name/name_or_your_company

Now move the new_fu.rb file into the directory name_of_your_company.

Your new_fu.rb file should now be in
app/vendors/plugins/new_fu/your_name/name_of_your_company/new_fu.rb

Start Autotest for Apllication
Open a terminal window and go to the root of your apllication
first type: rake spec
It should run through and sync the app with your rspec environment
Then type: autotest
The autostest should start and re-run everytime you change a file in your application

Set test environment
open a terminal window - locate the base of your app and type:
export RAILS_ENV=test

Start Autotest for Plugin
Open a terminal window and go to the root of your plugin directory
app/vendor/plugins/new_fu/
and type in autotest
The autostest should start and re-run everytime you change a file in your plugin

Set up Plugin init.rb file.
Locate the init.rb file in vendor/plugins/new_fu
add: include 'your_name/name_of_your_company/new_fu'

Set up Plugin as a module
Open your plugin file
vendor/plugins/new_fu/your_name/name_of_your_company/new_fu.rb
add the following.

.module YourName
....module NameOfYourCompany
.......module NewFu
.
...........def hello_world
..............puts "Hello World"
...........end
.
......end
...end
.end

Then in the new_fu_spec.rb file - located in vendor/plugins/new_fu/spec/ - add the following:

.require File.dirname(__FILE__) + '/spec_helper'
.
.describe YourName::NameOfYourCompany::NewFu, "" do
......include YourName::NameOfYourCompany::NewFu
.
......before do
......end
.
......it "should should say hello world" do
........hello_world
.....end
.
.end

The autotest should have passed on the tests and you should see "hello world" somewhere in the output.

######## To Be Continued.....
Further documentation.
Understanding and building plugins - Part I
Understanding and building plugins - Part II
Creating Plugins Manual
Autotesting while writing Rails Plugins

Montag, 1. September 2008

Rspec Helper Extention

Additional Helper Methods (except, with, only) in spec_helper.rb file in project_folder/spec/

class Hash

# filter key out of a hash
# {:a=>1, :b=> 2, :c=> 3}.except(:a)
# results of hash after call {:b=> 2, :c=> 3 }

def except(*keys)
self.reject { |k,v| keys.include?(k || k.to_sym) }
end

# override some keys with a new value
# {:a=>1, :b=> 2, :c=> 3}.with(:a => 4)
# results of hash after call {:a => 4, :b=> 2, c: => 3 }
def with(overrides = {})
self.merge overrides
end

# return a hash with only the pairs identified by the +keys+
# { :a=>1, :b=>2, :c=>3}.only(:a)
# results of hash after call {:a=>1}
def only(*keys)
self.reject { |k,v| !keys.include?(k || k.to_sym ) }
end

end