Associations are a set of macro-like class methods for tying objects together through foreign keys. They express relationships like “Project has one Project Manager” or “Project belongs to a Portfolio”. Each macro adds a number of methods to the class which are specialized according to the collection or association symbol and the options hash. It works much the same was as Ruby’s own attr* methods.
has_one
, has_many
, and belongs_to
.has_and_belongs_to_many
.Quick question: is there any way to create associations using multi-column primary keys in Postgre SQL?
Rails only recognized one field for a primary key. Maybe you can use a pg View to work around this?
Thanks very much, that works quite well.
Some helpful links:
Note: You can either install the following from source or build it with something like Darwinports, which has the option of installing everything under /usr/local
if you like.
/usr/local/mysql/bin/
sudo mv /usr/bin/ruby /usr/bin/ruby16
tar zxvf rubygems-0.8.4.tgz
cd rubygems-0.8.4
ruby setup.rb
sudo gem install mysql rails
and say “Y” to their dependencies.
./configure --with-mysql=/usr/local/mysql/bin --with-openssl
But in order to get a good compile I had to trick it a bit. The compile seemed to be ignoring my good mysql includes directory . So I added a symlink to point it in the right direction.
sudo ln -s /opt/local/include/mysql
/usr/local/mysql/include
It compiled, but i haven’t got mysql virtual hosting working yet. It’s fast though.(I’ve got a Darwin Ports portfile for lighttpd available on my site)
server.port = 8080
server.bind = "127.0.0.1"
server.event-handler = "freebsd-kqueue"
server.username = "www"
server.groupname = "www"
server.document-root = "/Users/USER/Sites/rails"
server.errorlog = "/Users/USER/Sites/rails/log/server.log"
server.modules = ( "mod_rewrite", "mod_fastcgi", "mod_simple_vhost" )
server.indexfiles = ( "index.php", "index.html" )
# simple virtual hosting
simple-vhost.server-root = "/Users/USER/Sites/rails/"
simple-vhost.default-host = "dev.example.com"
simple-vhost.document-root = "public"
# dev.example.com vhost
$HTTP["host"] == "dev.example.com" {
server.document-root = "/Users/USER/Sites/rails/dev.example.com/public/"
accesslog.filename = "/Users/USER/Sites/rails/log/access.log"
# rails stuff
fastcgi.server = ( ".fcgi" =>
( "localhost" =>
( "socket" => "/tmp/dev.example.com.socket",
"bin-path" => "/Users/USER/Sites/rails/dev.example.com/public/dispatch.fcgi"
)))
}
# mimetype mapping
mimetype.assign = (
".pdf" => "application/pdf",
".gif" => "image/gif",
".jpg" => "image/jpeg",
".jpeg" => "image/jpeg",
".png" => "image/png",
".html" => "text/html",
".txt" => "text/plain",
".css" => "text/css",
)
If you want to run it on port 80 remember to turn off Apache. You can shut it off with:
/System/Library/Startup Items/Apache/Apache stop
/etc/hosts
. For example, to get http://dev.mynewrailsapp.com working add:
127.0.0.1 dev.mynewrailsapp.com
This way you can get your browser to point at localhost instead of contacting the remote server.I’m working on my own big project at the moment – but along the way I’ve done a few things Rails developers on OS X might find helpful…
I am known as dema in the Rails community.
Started using Ruby on Rails in my computer science masters degree thesis on semantic web technologies, combining Active Record and the Action Pack with RDF and Sesame.
Currently, I am actively using Ruby on Rails on commercial web development projects.
I work as the chief software architect at Interface TI, my own start-up born within one of the most prestigious computer science universities in Brazil, PUC-Rio
Please contact me directly via email at demetrius (at) interface-ti (dot) com (dot) br.
If you’re interested in my ramblings regarding web software development in general and specifically, how Rails compares to ASP.NET, take a look at my weblog on http://dema.ruby.com.br.
Do you know your way around the Rails? Are you looking for work working with Rails? This is your page. Rails has a commercial ecosystem growing at steam speed and the opportunities to land contract or full-time employment has never been better.
Full Name: Two-line description with link to CV, demo applications, contributions made to Rails, and experience with Ruby and Rails.
If you’re looking to get your application done with Rails, you might also consider going with a firm that already has the expertise in-house. See Commercial Support.
Debian breaks up all the packages into smaller parts. This normally causes problems for new users.
If you are running Debian Unstable or Testing, or Ubuntu Warty or Hoary, see instructions at Rails On Ubuntu Debian Testing And Unstable.
Alternatively you can install all the Ruby Packages in Debian. One way to do this is described here: Howto Install Complete Ruby On Debian. The other follows below:
apt-get install irb1.8 libbigdecimal-ruby1.8 libcurses-ruby1.8 \ libdbm-ruby1.8 libdl-ruby1.8 libdrb-ruby1.8 \ liberb-ruby1.8 libgdbm-ruby1.8 \ libiconv-ruby1.8 libopenssl-ruby1.8 \ libpty-ruby1.8 libracc-runtime-ruby1.8 \ libreadline-ruby1.8 librexml-ruby1.8 \ libruby1.8 libruby1.8-dbg libsdbm-ruby1.8 \ libsoap-ruby1.8 libstrscan-ruby1.8 \ libsyslog-ruby1.8 libtcltk-ruby1.8 \ libtest-unit-ruby1.8 libtk-ruby1.8 \ libwebrick-ruby1.8 libxmlrpc-ruby1.8 \ libyaml-ruby1.8 libzlib-ruby1.8 rdoc1.8 ri1.8 \ ruby1.8 ruby1.8-dev ruby1.8-elisp \ ruby1.8-examples
If you get Adapter Not Found? errors when attempting to run Rails helper scripts, you are missing the database bindings.
apt-get install libmysql-ruby1.8
apt-get install libpgsql-ruby1.8
In case you want to use apache to serve your rails application, you need to enable mod_rewrite
. Using Apache 2 this can be done as:
a2enmod rewrite && /etc/init.d/apache2 force-reload
Using Apache 1.3 you might have to uncomment the appropriate line in your httpd.conf
or in the respective config file where module loading information is kept.
Setup Fast CGI to get production-level performance.
libapache2-mod-fastcgi
is only available in the unstable branch of Debian. Make sure you can use the unstable branch by checking /etc/apt/sources.list
for a line resembling:
deb ftp://ftp.debian.org/debian unstable contribThen:
apt-get install libapache2-mod-fastcgi a2enmod fastcgi && /etc/init.d/apache2 force-reload
Be cautious before you do this step: keep in mind that unstable means what it says. Allthough running packages from unstable is usually not problematic, there is no guarantee for it.
If installation of Ruby Gems fails with the message:
hook /home/dml/dloads/rubygems-0.8.3/./post-install.rb failed: You don't have write permissions into the /usr/lib/ruby/gems/1.8 directory.
You need to manually create the directories /usr/lib/ruby/gems
and /usr/lib/ruby/gems/1.8
The Ruby packages provided in Woody are version 1.6 (not adequate for running Rails). There is a way to install the “testing” packages which are 1.8 without the need to install a completely upgrade your distribution. It’s recommended that you first do this in a test environment to start with – updates are made to other core libraries which may impact on other services in a production environment.
You’ll need to make a change in /etc/apt/sources.list
first to tell apt to point to the desting packages: This assumes that you are running a UK installation of Debian, you may need to change te URLs according to your locale.
/etc/apt/sources.list
and comment out the line:
deb http://ftp.uk.debian.org/debian/ stable main non-free contrib
/etc/apt/sources.list
, add the line:
deb ftp://ftp.uk.debian.org/debian testing main
apt-get update
For reference: the following dependencies will also be installed:
libc6 libc6-dev libcomerr2 libdb1-compat libgdbm3 libkrb53 libncurses5 libpq3 libreadline4 libssl0.9.7 linux-kernel-headers locales tcl8.4 tk8.4 zlib1g
In addition, libnss-db
will be removed.
During the installation process you will see:
Preparing to replace libc6 2.2.5-11.5
This is an upgrade to the C Library and affects a number of services which will probably be running on your system. You will be prompted to confirm the upgrade and then whether to restart services. You ought to do this to ensure minimum conflicts and to make sure that the installation is stable. Else a reboot later on ought to flush the system and restart the services with the new library.
That ought to be it! You can then run ruby1.8
to test the installation (will probably need to refresh your login for the path to be refreshed and find the application)
irb1.8_1.8.2-2.1_all.deb libdrb-ruby1.8_1.8.2-2.1_all.deb liberb-ruby1.8_1.8.2-2.1_all.deb libiconv-ruby1.8_1.8.2-2.1_i386.deb libopenssl-ruby1.8_1.8.2-2.1_i386.deb libreadline-ruby1.8_1.8.2-2.1_i386.deb librexml-ruby1.8_1.8.2-2.1_all.deb libruby1.8-dbg_1.8.2-2.1_i386.deb libruby1.8_1.8.2-2.1_i386.deb libstrscan-ruby1.8_1.8.2-2.1_i386.deb libtest-unit-ruby1.8_1.8.2-2.1_all.deb libxmlrpc-ruby1.8_1.8.2-2.1_all.deb libyaml-ruby1.8_1.8.2-2.1_i386.deb libzlib-ruby1.8_1.8.2-2.1_i386.deb rdoc1.8_1.8.2-2.1_all.deb ruby1.8-dev_1.8.2-2.1_i386.deb ruby1.8_1.8.2-2.1_i386.debThanks to Ioan Bizau jr. who sent me this link
If you are compiling mod_fastcgi from source on a Debian platform and using the default Apache2 setup, you will need to retrieve the Apache2 source from the Debian repositories:
sudo apt-get install apache2-threaded-devThen you will be able to :
cd ..
tar -zxvf mod_fastcgi-2.4.2.tar.gz
cd mod_fastcgi-2.4.2
cp Makefile.AP2 Makefile
make top_dir=/usr/share/apache2
sudo make install top_dir=/usr/share/apache2
Edit your /etc/apache2/sites-enabled to something such as this:
NameVirtualHost *:80
<VirtualHost *:80>
ServerName localhost
ServerAdmin your@email.addy
DocumentRoot /var/www/
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
# This directive allows us to have apache2's
# default start page
# in /apache2-default/, but still have / go
# to the right place
RedirectMatch ^/$ /apache2-default/
</Directory>
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
ErrorLog /var/log/apache2/error.log
# Possible values include: debug, info, notice, warn, error,
# crit, alert, emerg.
LogLevel warn
CustomLog /var/log/apache2/access.log combined
ServerSignature On
Alias /doc/ "/usr/share/doc/"
<Directory "/usr/share/doc/">
Options Indexes MultiViews FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
Allow from 127.0.0.0/255.0.0.0 ::1/128
# this is for a localhost setup, your needs may be
# different on a production server
</Directory>
</VirtualHost>
<IfModule mod_fastcgi.c>
FastCgiIpcDir /tmp/fcgi_ipc/
</IfModule>
<VirtualHost *:80>
ServerName rails
DocumentRoot /path/to/rails/app/public/
ErrorLog /path/to/rails/app/log/apache.log
ServerAdmin your@email.addy
<Directory /path/to/rails/app/public/ >
Options ExecCGI FollowSymLinks
AllowOverride all
Allow from all
Order allow,deny
</Directory>
</VirtualHost>
Then, create a file /etc/apache2/mods-enabled/fcgi.load and add the following lines to it:
LoadModule fastcgi_module /usr/lib/apache2/modules/mod_fastcgi.so AddHandler fastcgi-script .fcgi
How to install Apache, Ruby, Ruby Gems, Rails, and Fast CGI under Linux
su root
cd /usr/local/src
wget http://xyz.lcs.mit.edu/ruby/ruby-1.8.2.tar.gz
wget http://rubyforge.org/frs/download.php/3700/rubygems-0.8.10.tgz
wget http://www.fastcgi.com/dist/fcgi-2.4.0.tar.gz
wget http://www.fastcgi.com/dist/mod_fastcgi-2.4.2.tar.gz
wget http://mirrors.ccs.neu.edu/Apache/dist/httpd/httpd-2.0.53.tar.gz
tar -zxvf ruby-1.8.2.tar.gz
cd ruby-1.8.2
./configure
make
make test
make install
cd ..
tar -zxvf rubygems-0.8.10.tgz
cd rubygems-0.8.10
ruby setup.rb
:
Install required dependency rake? [Yn] y
Install required dependency activesupport? [Yn] y
Install required dependency activerecord? [Yn] y
Install required dependency actionpack? [Yn] y
Install required dependency actionmailer? [Yn] y
Install required dependency actionwebservice? [Yn] y
:
cd ..
tar -zxvf httpd-2.0.53.tar.gz
cd httpd-2.0.53
./configure --enable-rewrite --enable-cgimak
make
make install
cd ..
tar -zxvf fcgi-2.4.0.tar.gz
cd fcgi-2.4.0
./configure
make
make install
cd ..
tar -zxvf mod_fastcgi-2.4.2.tar.gz
cd mod_fastcgi-2.4.2
cp Makefile.AP2 Makefile
make
make install
gem install rails
gem install fcgi
/usr/local/apache2/conf/httpd.conf
or /etc/httpd/conf/httpd.conf
) and add these lines:
<Directory /var/www/>
AllowOverride all
</Directory>
LoadModule fastcgi_module modules/mod_fastcgi.so
AddHandler fastcgi-script .fcgi
<VirtualHost *:80>
ServerAdmin webmaster@host.com
DocumentRoot /var/www/rails/testapp/public
ServerName www.host.com
ErrorLog /var/log/httpd/testapp-error_log
CustomLog /var/log/httpd/testapp-access_log common
Options Indexes ExecCGI FollowSymLinks
RewriteEngine On
</VirtualHost>
/usr/local/apache2/bin/apachectl start
cd /var/www/rails/testapp/public
rm index.html
cd ..
script/generate controller home index
/var/www/rails/testapp/public/.htaccess
and change dispatch.cgi
to dispatch.fcgi
/var/www/rails/testapp/public/dispatch.fcgi
and change
require 'fcgi'
to
require 'rubygems'
require_gem 'fcgi'
It is important to know that the validation macros in Active Record (such as validates_presence_of, validates_length_of do not perform any whitespace stripping (so ” ” – three spaces in a row – will pass the validation of length of 2 and so on). Besides, empty strings (””) are not treated as being NIL by these validation rules.
Most of the time this is absolutely not something you want (basically anyone will be able to type 5 spaces into a field which will make it valid and present).
For this you can use an Observer that filters every Active Record before it gets validated.
The observer is:
class WhitespaceKiller < ActiveRecord::Observer
observe ModelClass1, ModelClass2 #all your model classes
def before_validation(record)
record.attributes.each do | attr, val|
if !val.nil? && val.respond_to?(:strip)
s = val.strip
s.size == 0? record[attr] = nil : record[attr] = s
end
end
end
end
It is a good idea to put your observer into the “lib” directory of your app. After you save it include the following into your environment:
require File.dirname(__FILE__) + '/../lib/whitespace_killer'
WhitespaceKiller.instance
Please note that you have to explicitly create an instance of your observer (observers are meant to be instantiated from controllers, and before you make an instance your observer will not work – but we cheat and make an instance ourselves).
After that all models that you mentioned in the observer will be filtered before validation. As a bonus it will replace empty strings with real NIL so that validation errors will be raised for empty strings too.
See the Rails cookbook: Using HTTP Caching
A web application is server side handled interactive website, in its simplest form.
Traditionly a Website is simply a collection of pages with information on them, and you click different links to view different information. In a web application users, or administrors, submit data to the server, and it is reflected in the output, make it more interactive.
Message Boards?, Shoppings Carts?, and Blogs? are all examples of Web Applications.
see Understanding Web Applications for more info
development:
adapter: mysql
database: rails_development
host: localhost
username: root
password:
test:
adapter: mysql
database: rails_test
host: localhost
username: root
password:
production:
adapter: mysql
database: rails_production
host: localhost
username: root
password:
why not
development:
adapter: mysql
database: myappname_development
host: localhost
username: root
password:
test:
adapter: mysql
database: myappname_test
host: localhost
username: root
password:
production:
adapter: mysql
database: myappname_production
host: localhost
username: root
password:
—
This doesn’t really solve anything does it? Whether it’s ‘rails’ or ‘MyAppName’ the user still has to go in there and change it to whatever they want it to be. Also you’d want to use ‘myappname’ camelcasing the database name is not a great idea. —Schubert
—
My thought when I was using it was that having to change it from rails to myappname was a minor pain that would be easy to fix. If I create three apps they all access the same db. why not just prefix with the appname instead then those of us that aren’t picky don’t have to change it, and those that do can. Does that make sense?
changed to all lowercase the appname :-)
(Whats wrong with camelcasing the database name?)
—dru
see Alex Wayne
Some official “Powered by Ruby on Rails” logos that web designers could incorporate into site layouts would help raise awareness for Rails (not that is has a problem with that lately)
Also many developers are proud to be using rails, and want to show it off.
Its just one more thing to add the final touches of full package professionalism.
Use either:
escapehtml(someStringToBeEscaped)
Or the shorthand:
h(someStringToBeEscaped)
Question: Is there anyway to automatically escape all rendered HTML without having to explicitly call escapehtml
?
_Answer_(or at least, one of many possible answers): It should be fairly simple, but I don’t think you’d want to. That would result in the readers just seeing raw HTML (as if they had chosen “view source”).
I think you meant to ask “Is there anyway to automatically escape all _______ HTML without having to explicitly call escapehtml
?” but I don’t know what you want in the blank. “User entered”? “SQL fields embedded in”? “tainted”?
————
I believe the easiest way to handle this is instead of:
<%= @foo.text_to_escape %>
use this:
<%=h @foo.text_to_escape %>
This will esacpe all html characters and you only do this where it is necesary, meaning where site goers have the oppurtunity to enter data.
I am a Ruby on Rails developer that has been truly enlightened by this framework. Before I did web design because it paid well and I was good at it. Thanks to Rails, I do it for fun.
Nothing to show… yet…
see Ruby Gems
This page is part of the ongoing Documentation Discussion
Some notes about the suitability of Hieraki as the basis for RoRDoc.
Wiki Gardening required. This document was (roughtly) cut out of Documentation Discussion and could use a good scrubing down.
LeeO: I propose that Hieraki(http://hieraki.org/) be used as the basis for a centralized, managed Ruby on Rails manual. Hacking/expanding will definitly be required (see “Using Hieraki for RoRDoc?” above) but I think it makes more sense to use the foundation already available.
This page is part of the ongoing Documentation Discussion
Wiki Gardening required. This document could use a good scrubing down.
We should consider the UI exposed to different Ror Doc Users? (since the requirements/tasks of a user will be quite different than those of a RoR developer, or documentation maintainer)
http://PHP.net’s comments are at times more useful than the docs proper. We need to look at
Ruby Conf is, well, the Ruby Conference.
You can access http://www.rubyconf.org/ to get more informations.
The rubyconf is held in USA, european people may like to partecipate at EuRuKo
, (held in Munich 9 and 10 of october 2004).
Inno DB is a table engine that is available in My SQL.
Unlike those of the default My ISAM? engine, Inno DB tables suport foreign key constraints, transactions, and row level locking.
To use Inno DB table, specify ENGINE=InnoDB
when creating a table, for example:
CREATE TABLE customers (id INT, name VARCHAR (40), INDEX (id)) ENGINE=InnoDB;
If you set default-table-type = InnoDB
in the [mysqld]
section of my.cnf, all new tables will be Inno DB, instead of My ISAM?.
More information is available in the MySQL Reference Manual :
Consolidating all tutorials here, instead of scattered on the main community page …
Vincent Foley? has written a tutorial on how to write a simple todo list program with Rails. You can get it from multiple places:
O’Reilly Article on getting started using Rails within Windows and creating a recipe book application.
How to make a (small) publication management app
A wiki based tutorial that walks you through setting up Rails, and then creating a contact book application.
Scott of Elite Journal fame is partway through a multi-part dissection of a Rails application. Great stuff on models here that doesn’t seem to be available anywhere else so far.
this is written & produced by Amy Hoy. a self-proclaimed renaissance woman who enjoys designing, coding, and writing for herself and others (but mostly for herself). In her spare time she enjoys cooking, mucking about in her darkroom, and writing about herself in the the third person.
You’ve gotta learn Ruby before using Rails, right? Here’s a weblog series by Al Abut to learn Ruby over the course of three weeks while blogging out every day:
see Fast CGI
Confused by an odd word or phrase you saw on this Wiki?
You’ve come to the right place. This is a collection of words and phrases that have found special use in the Ruby on Rails community. You’re just one click away from instant enlightenment.
If the word you wanted to look up isn’t here, please edit the page and add it (along with reference to where you saw it, if you remember). That way the next person who knows the word to drop by can add a definition.
(aka Tom Sawyer)
The Ruby lover that everyone loves to hate, who rarely finishes a damn thing, and has more ideas then he knows what to do with—some good, some bad and alot more that just vanish with out a trace.
Current Projects:
I’m a Brazillian web apps developter trying out rails
For the moment error messages are embeded inside the rails code…rails should give an option to specify the language of the app…so error messages have to be took of the code to an xml or txt file…someone for that patch ? :D
—technoweenie
This sounds like a good idea, although I think using yml would be a better fit. Perhaps someone could write up an ActiveResource class that looks up properties in /config/languages/en-us.yml.
—-
At the bottom of config/environment.rb I have the following code that sneaks in german error messages for validation failures. I doubt that this is a clean way, but apparently it’s the only one possible right now. But I’m still a newbie, thus add a large grain of salt.
module ActiveRecord
class Errors
begin
@@default_error_messages.update( {
:inclusion => "ist nicht in Liste gültiger Optionen enthalten",
:invalid => "ist ungültig",
:confirmation => "entspricht nicht der Bestätigung",
:accepted => "muss akzeptiert werden",
:empty => "darf nicht leer sein",
:too_long => "ist zu lang (höchstens %d Zeichen)",
:too_short => "ist zu kurz (mindestens %d Zeichen)",
:wrong_length => "hat eine falsche Länge (es sollten %d Zeichen sein)",
:taken => "ist schon vergeben",
:not_a_number => "ist keine Zahl",
})
end
end
end
see also Overriding Rails Messages In Another Language
—Henrik Horneber
couldnt this be used to internationalize all rails messages ?
http://ri18n.berlios.de/
—Giovanni Degani
“Die Geister, die ich rief”—Please, no. This way of overriding is a stop-gap measure, not a general good practice. Doing things like this ties the new code very tightly to the internal structure of Rails. This is the kind of code I expect to break one time or another with a new version of Rails.
The proper way, IMHO, is to use one of the gettext derivatives and wrap all user visible text occurring in Rails in _()
. In cases where no localization exists, the english strings just pass through the _()
. Where there are localized messages, they are used.
Michael, i guess you didnt understand me..
I was talking about using this: http://ri18n.berlios.de/
to internationalize the framework.
:)
I like Gavin Sinclair’s idea of the “Understanding Rails” section, though I slightly favour calling the top node simply “Understanding”.
As I’ve mentioned elsewhere, what I think we need is a mesh of small pages linked together in multiple ways, so that users with different needs can all navigate successfully.
To that end, I am trying to do multiple things:
The generic part of this was simple (see Howto Setup Apache With Fast CGIAnd Ruby Bindings). Since the PHP Nuke installation was only part of our site (and we are planning to use rails elsewhere) we also needed to learn Howto Deploy More Than One Rails App On One Machine.
in Using Rails To Gradually Replace ARunning PHPNuke Installation,).
In summary, I’d like to see:
[Snipped some no-longer-relevant discussion.]
The Understanding Rails page is coming along nicely now.
I’ve had a thought for another top-level category: Resources. It’s not a pretty word to fit into a page title (e.g. ResourcesAvailableGenerators), but it’s a very important concept, so maybe someone can think of a better name.
The basic idea is this: people create useful resources to be used with Rails (generators, helpers, related libraries like “search”, etc.) and they get announced on the mailing list and that’s it. Someone starting with Rails a few months from now will have missed those announcements and will not know of such things. Of course, they can ask on IRC or the mailing list, but I think a Wiki category documenting the available third-party resources is a good idea.
At the moment, I’m adding “category: Resource” to any page I see which fits the bill—only one so far. If a number of such pages turn up, then a top-level “Resources” page (i.e. linked from the home page) might be justified.
There is an idea floating around (called Boxcars? by some people) that I think needs to be fleshed out & run with. Basically, a Boxcar is a semi-standalone piece of a Rails Application—something like a module in other frameworks—that you can hook-in to your Rails Application and have it “just work”. The Search Generator or Authentication-stuff seems to fit the bill nicely. Instiki would probably be one of the largest “Boxcars” if made into one; most helpers would probably be too small to count. I think one of the first goals is to make them Gem-able.
I like the idea, but I’m on the border of over commited at the moment (just moved to a new country, learning a new language, have two pre-school kids, a full time job, am semi-active in several open source projects, and have commited to do quite a bit on this wiki…and I’m sure I’m forgetting something…)
But I do strongly support the idea of “Boxcars” and (to coin a phrase in the same vein) smaller “Ties” that you can just drop into your helpers directory.
—Markus QCREATE TABLE users (
id serial PRIMARY KEY,
nick character varying NOT NULL,
name character varying,
"password" character varying NOT NULL,
modified timestamp with time zone
DEFAULT now() NOT NULL,
created timestamp with time zone
DEFAULT now() NOT NULL,
"access" timestamp with time zone
);
CREATE TABLE roles (
id serial PRIMARY KEY,
name character varying NOT NULL,
info character varying
);
CREATE TABLE permissions (
id serial PRIMARY KEY,
name character varying NOT NULL,
info character varying
);
CREATE TABLE users_roles (
user_id integer REFERENCES users ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
role_id integer REFERENCES roles ON UPDATE CASCADE ON DELETE CASCADE NOT NULL
);
CREATE INDEX ur_map_idx ON users_roles USING btree (user_id, role_id);
CREATE TABLE permissions_roles (
role_id integer REFERENCES roles ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
permission_id integer REFERENCES permissions(id) ON UPDATE CASCADE ON DELETE CASCADE NOT NULL
);
CREATE INDEX rp_map_idx ON permissions_roles USING btree (role_id, permission_id);
Could someone make a My SQL version?
require 'active_record'
class Permission < ActiveRecord::Base
has_and_belongs_to_many :roles
end
class Role < ActiveRecord::Base
has_and_belongs_to_many :permissions
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
has_and_belongs_to_many :roles
end
Get the user associated with id #1:
user = User.find(1)
Get the roles associated with this user:
roles = user.roles
Get the permissions for the first role associated with the user:
perms = roles.first.permissions
Add role #2 to the user:
role = Role.find(2)
user.add_roles(role)
user.save
NOTE: Supposedly the above is old syntax, and you should do this instead:
role = Role.find(2)
user.roles << role
user.save
Add a few more permissions to role #2:
role.add_permissions(Permission.find(2), Permission.find(3))
role.save
Remove one of the permissions again:
role.remove_permissions(Permission.find(3))
role.save
See also ACLController
Im a Brazillian web apps developter trying out rails
This is an automatically generated (but not automatically updated) list of the pages that were wanted (by some other page) at the time I (Markus Q) last ran it. It does not include missing author pages. I created it mostly for my own convience, but decided to share.
If you have any questions or comments, drop me a Wiki Mail.
NOTE: This page is auto generated so don’t bother trying to maintain it. Instead, if you want to pitch in and help, try fleshing out some of the wanted pages.
4370917 bytes
883 pages
443 shy authors.
This is a simple method to get multiple rails sites up and running for a default Text Drive setup.
With more advanced setups the rewriting rules may not work (e.g. if you don’t have mod_vd), in which case the alternative is to add a new virtual host container (submit a support request if you don’t know how).
Q:[What if there is no sites/ directory? What if all you have are Maildir/, etc/, logs/, public_html/, cgi-bin/, home/, php-fastcgi/, and svn/ ?A: You mkdir and make one. mkdir sites or mkdir ~/sites.
To create a rails app, do the following:
1. run the command “rails sites_directory/app_name”
2. run the command “ln -s sites_directory/app_name/public/ /usr/home/your_username/public_html/app_name”
3. ensure the following is in your .htaccess file (in public_html)
AddHandler fastcgi-script .fcgi AddHandler cgi-script .cgi Options +FollowSymLinks +ExecCGI RewriteEngine On
4. add the following lines to the same .htaccess file (i.e. once for each app).
If you have html files that should not be handled by rails, use this:RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ /dispatch.fcgi?$1 [QSA,L]to make sure that local files are displayed. To redirect everything to rails just use this:
RewriteRule ^(.*)$ /dispatch.fcgi?$1 [QSA,L]
NB: By default Text Drive is set up to magically allow sub.your_hostname.com
to point to your_hostname.com/sub
which causes problems with routes and rewrites. You can either use a virtual host as explained by octopod, or you can remove the *.your_hostname.com
entry in Webmin > Apache Webserver > virtual server for your_hostname.com
> Networking and Addresses. Remember to apply changes.
map.connect ':controller/:action/:id'and add the name (and action) of your controller like this:
map.connect ':controller/:action/:id', :controller => '_your_default_controller', :action => '_your_action'The action defaults to ‘index’, so if you don’t want to call ‘new’ or something like that, just leave out the action-part.
5. setup your database and rails config file. You are in a shared environment so you need to put your mysql user and password in the database.yml file
production: adapter: mysql database: {YOUR TEXTDRIVE MYSQL DATABASE} host: localhost username: {YOUR TEXTDRIVE MYSQL USER} password: {YOUR TEXTDRIVE MYSQL PASSWORD}
if you have your Rails environment set to “development” (the default), instead of “production” you need to change it.
Add the follow line just after the shebang (the first line) in config/environment.rb:
ENV['RAILS_ENV'] = "production"
6. code away!
As you may read on the above link, it might be good to submit a ticket for a virtual host on your Rails directory, or else the rewrite rules may act funny or don’t work at all – Nicolas Mommaerts
See also Fast CGI on unix linux bsd
Robert has been designing and developing websites from small publications through enterprise applications since 1998.
His skills include the .Net languages, XHTML, CSS, Java Script, and his newest (and favorite) Ruby On Rails.
Robert can be reached at http://www.simplicio.com
He is also building a community support forum for the Meditech Health Care Information System, used by over 2000 hospitals world-wide, at http://www.MeditechAnswers.org
Robert is currently working on an open source project rolling on Rails for the Medical community. This profile will be updated when it is ready for consumtion.
In many applications, you’ll find that your edit and new views are basically the same. A common annoyance can be that if you change the model and add a new attribute, you are forced to do the change in both views, edit and new.
This violates the principle of “Don’t Repeat Yourself”, and Rails can help you solve it by letting you easily reuse the edit view as the new view of a model.
First make a new variable that holds the “mode” of the view you are in. The two modes might be called “edit” and “new.” You want your form to post to specific controller methods depending on the mode.
Add an if branch to the view.<% if @mode == "edit" -%>
<%= start_form_tag :action=> "edit", :id => @member.id %>
<%= hidden_field "member", "id" %>
<% else -%>
<%= start_form_tag :action=> "new" %>
<% end -%>
Then create methods in the controller that can handle these modes:
def edit
@member = Member.find(@params['id'])
@mode = "edit"
# will use the "edit.rhtml" template by default
end
def new
@member = Member.new()
@mode = "new"
render_action "edit"
end
The tricky part is the render_action “edit” one in the new method. This call uses the “edit.rhtml” template to render the view instead of the default “new.rhtml”. and therefore makes it possible to reuse the template.
Thanks to noradio on #rubyonrails for pointing this out, and clarifications by msp here.
Here’s how I do it (with thanks to you for the original idea). This doesn’t require the @mode
variable.
In my edit.rhtml
I use:
<% if @params['action'] == "new" %>
<h1>New part</h1>
<%= start_form_tag :action=> "create" %>
<% else %>
<h1>Edit part</h1>
<%= start_form_tag :action=> "update", :id => @part.id %>
<%= hidden_field "part", "id" %>
<% end %>
In the controller I have:
def new
@part = Part.new
render_action 'edit'
end
def create
@part = Part.new(@params['part'])
if @part.save
flash['notice'] = 'Part was successfully created.'
redirect_to :action => 'list'
else
render_action 'edit'
end
end
def edit
@part = Part.find(@params['id'])
end
def update
@part = Part.find(@params['part']['id'])
if @part.update_attributes(@params['part'])
flash['notice'] = 'Part was successfully updated.'
redirect_to :action => 'show', :id => @part.id
else
render_action 'edit'
end
end
Thanks, JJ
def auto_form
action = case controller.action_name
when "new" then "create"
when "edit" then "update"
else controller.action_name
end
start_form_tag :controller => controller.controller_name, :action => action
end
Now you can start your forms with:
<%= auto_form %>
Which seems a lot cleaner to me. It’s also possible to make use of ActiveRecord::Base#new_record? ( http://rails.rubyonrails.com/classes/ActiveRecord/Base.html ) to determine if this is a new object.
<% if @params['action'] == "new" %>
with
<% if @params['action'] == "new" or
@params['action'] == "create" %>
—adam sanderson
Is there any reason not to merge “new” and “create” into one controller? (Likewise with “edit” and “update”). If you do that, you can use <%= form_tag %> with no arguments at all, and it will generate the url for the current controller, so you don’t have to detect which controller you’re in.
—tyler kiley
This is a test to see how this works.
Rails has the concept of environment to represent the stages of an application’s lifecycle (test, development, and production are the defaults). Errors are handled as appropriate for the deployment target. The test and development environments provide developer-relevant error handling whereas the production environment returns an error page with HTTP status 500 (Application Error).
The API docs for ActionController::Rescue explain how to use the rescue_action_in_public
to deal with uncaught exceptions.
To configure the error page returned by your Rails application, in a global or controller specfifc way follow these instructions. It is possible to combine these approaches and have a global default and be able to override it in individual controllers.
Globally: Navigate to your apps /controller directory and edit application.rb:
def rescue_action_in_public(exception) render_text "<html><body><p>There was a global error processing your request.</p><!-- #{exception} --></body></html>" end def local_request? false end
Controller specific: Edit the controller you would like to have respond to errors differently to include it own implementation of rescue_action_in_public:
def rescue_action_in_public(exception) render_text "<html><body><p>There was a controller specfic error processing your request.</p><!-- #{exception} --></body></html>" end
These examples show simple text rendering for error pages, but it is possible to do anything you would like (email, logging, redirects, etc.) in the rescue_action_in_public
method(see Howto Send Email When Rails Throws An Exception, for example).
When working on this functionality locally you will need to make sure that your /config/environments/development.rb has the following set in it:
ActionController::Base.consider_all_requests_local = false
Also, despite defining local_request?
as above, you may have to change the address used to make the request. Neither localhost
, not 127.0.0.1
work, instead use the actual IP address of your machine.
You don’t need to know this.
Really.
But if you’re like me, you find it hard to step off the cliff and walk across the open air—even if all your friends are doing it—without at least some understanding of the magic that makes it all work.
The big picture is this:
A request come in to the webserver. In the normal course of things, it winds up resolving to something off the public
directory of your application, which contains a .htaccess file that redirects it to the CGI script public/dispatch.cgi
unless a file by that name already exists. The dispatcher invokes some libraries that use the contents of your config/routes.rb
to decide what controller to use and what method of the controller to call.
If that satisfies you, you’re quite welcome, and we hope you enjoy the rest of your Rails experience.
For the rest of you, that just must know the details, I won’t bother reminding you that you probably don’t need to know them because it ’s unlikely to work any better on you than it did on me. And who knows, maybe you do need to know it, in your persuit of some grand leap of Rails wizardry that will leave us all slack-jawed in amazement? Who am I to stand in the way of that?
So here goes. The details are both nitty and gritty, but at least when we’re done you’ll know what’s happening.
Let say, for example, that it’s Apache (though it could just as well be WEBrick or Lighttpd—the ideas are the same even if the syntax is a little different).
The request contains a URL such as “/recipies/show/1
” or “/rails/new/UnderstandingHowRequestsAreRouted
.”
If you followed along in Howto Setup Apache With Fast CGIAnd Ruby Bindings or something similar1, your httpd.conf
file will contain something like this (omitting the lines that don’t affect the routing):
<Directory /var/www/>
AllowOverride all
</Directory>
<VirtualHost *:80>
DocumentRoot /var/www/rails/testapp/public
</VirtualHost>
1 (Slightly more complex configurations, such as described in Howto Deploy More Than One Rails App On One Machine, are explained below, after we’ve got the basics down.)
This tells Apache to treat all URLs as if they were relative to the directory /var/www/rails/testapp/public
(so our example URLs would be converted into “/var/www/rails/testapp/public/recipies/show/1
” and “/var/www/rails/testapp/public/rails/new/UnderstandingHowRequestsAreRouted
.”
respectively.
It also tells Apache to directories under /var/www/
(which these are) to have there own special per-directory instruction that can override anything they want to. How does they do that?
It lives in the public directory of your Rails App, and it looks something like this (again, omitting lines that don’t concern us here):
# Redirect all requests not available on the filesystem to Rails
RewriteEngine On
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
This is where we override any the base Apache configuration to set off the Rails magic. In order, the RewriteRules:
dispatch.cgi
There are a few things to note here:
AddHandler fastcgi-script .fcgi
AddHandler cgi-script .cgi
Options +FollowSymLinks +ExecCGI
These tell Apache that dispatch.cgi (or .fcgi) is a program, and that it should run it to handle the request.
In either case, it’s a very short program, and they are essentially the same as far as routing is concerned:
#!/usr/local/bin/ruby
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
require "dispatcher"
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
Dispatcher.dispatch
Chunk by chunk:
config/environment.rb
is required and should be treated as part of this filedispatcher.rb
is required and should be treated as part of this file (and as we’ll see in a moment, that’s where the fun starts). Note that your copy may not be in the directory mentioned in the comment—if for no other reason than the path given is specific to Rails version 0.80 and you are almost certainly using something newer.This library is again pretty small (only a few dozen lines, including the copyright notice & Open Source licence), but we only care about a small part of it (using ":"
to indicate omited lines):
:
class Dispatcher
:
def dispatch(cgi = CGI.new, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS)
:
request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi)
prepare_application
: ActionController::Routing::Routes.recognize!(request).process(request, response).out
:
end
private
def prepare_application
ActionController::Routing::Routes.reload if Dependencies.load?
:
end
end
end
The omited code is mostly error handling and logic to load/flush/reload base data when needed. Remember that your Rails App can accept changes “on the fly” without needing to restart or reconfigure anything? Some of that magic is handled here.
The only one we care about is the loading of routes (from your “config/routes.rb
“). These are used by the Action Controller when it is asked to “recognize!” the request (which it constructs from the CGI request data that the script was passed by the web server—that’s where your (rewritten) path lives at this point in the process).
ActionController::Routing::Routes.recognize!
At this point the path of the request looks something like:
/recipies/show/1
(stored in request.request_uri
) and the script name (which can be found in request.env["SCRIPT_NAME"]
is something like /dispatch.cgi
. Note that the script name really the path to the script from the Document Root…in other words, it starts with a ”/”.
From these the Action Controller computes the path we care about by taking the request_uri and chopping off whatever is left of the Document Root path—but since it doesn’t have access to Apache’s internal variables, it has to guess. So it assumes that whatever the prefix that needs to be chopped off is, it will be the same for the URL and the script. So the code looks like this:
actionpack…/lib/action_controller/request.rb
# returns the interpreted path to requested resource after
# all the installation directory of this application was taken into account
def path
path = request_uri ? request_uri.split('?').first : ''
# cut off the part of the url which leads to the installation directory of this app
path[relative_url_root.length..-1]
end
# returns the path minus the web server relative
# installation directory
def relative_url_root
File.dirname(env["SCRIPT_NAME"].to_s).gsub /(^\.$|^\/$)/, ''
end
And the result is a string such as “/recipies/show/1
”, which winds up in being the request.path
The request path is then matched against the routes from your config/routes.rb
until one of them matches. Note that this means the most general rules should come last, otherwise they will gobble up all the requests.
Using Introspection, the system can call…
If you’re running multiple Rails application on the same machine you’ve probably got a slightly more complicated situation…but only slightly.
Typically, the http.conf
configuration will not map the Document Root to the public
directory of your Rails application (for one thing, how would it know which one to use?). Instead, Rails requests will be rewriten individually by rules like the ones in the .htaccess file, with the end result that they end up mapping to the right public
directory, just as if they’d come in the old fashioned way.
But dispatch.cgi
was there all along, and since it didn’t go through the extra round of URL rewriting, it probably won’t wind up with the same directory prefix. Consequently when the Action Controller trys to do it’s stuff, it will wind up chopping an arbitrary part of the URL off and…well, let’s just say it isn’t pretty.
Fortunately, Apache provides a directive (Rewrite Base?) to handle just this situation. It can be used in your .htaccess file to make the directory prefixes for the rewritten URLs and the dispatch.cgi
match again, and from that point on everything works just as it did before.
ApplicationController is an abstract controller from which all other controllers inherit. All controllers decend from this super layer.
It is an empty controller to which you add filters that should be run on all controllers and methods that should be available to all controllers.
It comes with an Application Helper as well where you can place methods that all templates should have access to.
Pre Rails 0.9.0, the ApplicationController was know as Abstract Application Controller (which was introduced in Rails 0.6.0).
Some functionality obviously missing from String
and Array
.
module PrefixSuffix
def prefix(length)
self[0 ... length]
end
def suffix(length)
self[-length .. -1]
end
def cut_after(prefix_length)
return self[0 ... prefix_length], self[prefix_length .. -1]
end
def starts_with?(s)
if self.kind_of?(String)
index(s) == 0
else
prefix(s.length) == s
end
end
def ends_with?(s)
if self.kind_of?(String)
index(s, -(s.length)) != nil
else
suffix(s.length) == s
end
end
def without_prefix(p)
prefix, suffix = cut_after(p.length)
if prefix == p
suffix
else
self
end
end
def without_suffix(s)
prefix, suffix = cut_after(-(s.length))
if suffix == s
prefix
else
self
end
end
end
class String
include PrefixSuffix
end
class Array
include PrefixSuffix
end
Rails already does a good job of displaying validation error messages and provides for styling them using CSS.
Maybe you want to display these kinds of errors entirely differently. Let’s say you don’t want to show messages in a single block, instead you’d like to tack them onto the individual fields. Now, you don’t have to change code somewhere deep in the bowels of Rails. A hook for customization is already there: ActionView::Base.field_error_proc
. That class variable holds a Proc
object that is used to render input elements with errors.
Keep in mind, that this error proc only applies to tags inserted via one of the various helper methods. It does not automagically wrap itself around HTML tags you write manually.
Here’s an example of a field_error_proc
that puts the error message in the field’s title. Multiple messages are nicely bulletted.
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
msg = instance.error_message
title = msg.kind_of?(Array) ? '* ' + msg.join("\n* ") : msg
"<div class=\"fieldWithErrors\" title=\"#{title}\">#{html_tag}</div>"
end
Where does this code go? A good place is at the end of config/environment.rb
. Better still, put it in another file that is included there.
Of course, when validation did result in errors, you can’t count on users to search around with the mouse to see error message. So let’s make it a little easier for them by tinting the background of failing input widgets with an alarming color.
.fieldWithErrors {
display: inline;
}
.fieldWithErrors input, .fieldWithErrors select {
background-color: #ffdfdf;
}
Now, there’s still something missing. With the code above, you don’t get to see errors related to associated objects chosen with FormOptionsHelper#select
or FormOptionsHelper#collection_select
. This is because those methods work not on the association itself, but rather its foreign key field. As validation errors are related to the association, not its foreign key field, no error message will be available for the select. As almost always in Ruby and Rails, there’s a way to code around this. Make sure the code below is loaded (see Overriding Rails Messages In Another Language) and foreign key fields are treated like their corresponding associations.
module ActiveRecord
class Errors
alias_method :on_without_id_stripping, :on
def on(attribute)
on_without_id_stripping(attribute.to_s.without_suffix('_id'))
end
end
end
You may notice that I’ve cheated. String#without_suffix
isn’t defined in Ruby. But it is at Prefix Suffix.