Related <select> Dropdowns in Rails Views
This is a pretty common scenario (I would think). You have a nested model that you want to be able to select the item that the current item depends on (the client for a project, the manufacturer for an appliance). Using form_for, you can do something like this.
Chat with JTJ:
What you do is create a select tag with the “
select” method like so: (using the client/project scenario)
f.select(:client_id,The next value you pass to the select method has to be an array of text/value pairs
like this:
[ [ "Jason Johnson", 1], ["Trey Piepmeier", 2], ["Royall", 3] ]In order to create this array, you do a find on your clients table and use Ruby’s “
collect” method.like so:
Client.find(:all).collect {|c| [ c.name, c.id ]}So, altogether now:
f.select(:client_id, Client.find(:all).collect {|c| [ c.name, c.id ] })
Other sources:
Title Case in ERb
Use .titleize or .titlecase. I’m using this in the <title> tag of my application.rhtml:
<%= controller.action_name.titleize %>
Source
Setting up a new Rails project in Subversion
Create a folder to put all the junk you need to set things up.
mkdir svn_setup
cd svn_setup
Create the standard SVN folder structure.
mkdir tags
mkdir branches
Create a new Rails project and rename it to be the trunk folder.
rails project_name
mv project_name trunk
The reason to do this is so your database.yml file (among others) will have the right project name instead of trunk_development, etc.
A little housekeeping before putting the files into the repository.
cd trunk
rm -r tmp/*
rm -r log/*
mv config/database.yml config/database_example.yml
Put the files into the repository.
cd ..
svn import . svn_project_url -m "initial import of blank Rails project" --username whathaveyou
Checkout the files and tell Subversion to ignore some files.
cd ..
svn co svn_project_url/trunk project_name
cd project_name
cp config/database_example.yml config/database.yml
svn propset svn:ignore database.yml config/
svn propset svn:ignore "*" log/
svn propset svn:ignore "*" tmp/
If you want, setup Rails with svn:externals to that it will be ready for you to lock it into a particular version for stability.
svn propedit svn:externals vendor/
In the file that pops up, enter this (or enter whatever version you want to use–such as http://dev.rubyonrails.org/svn/rails/trunk/ for edge):
rails http://dev.rubyonrails.org/svn/rails/tags/rel_1-2-3/
Save then close the file.
Check the changes back into the repository.
svn ci -m "Ignore database.yml, log/, and temp/. Set up Rails with svn:extnrnals"
Then update your checkout to get the Rails external to load.
svn up
Other things:
When you’re done with everything you can delete the svn_setup folder. I think I’m going to keep mine around for a slight head start on more projects.
Don’t forget to use the -c option when you run script/generate to automatically add the files to Subversion.
script/generate scaffold_resource angryfarmer name:string bales_of_hay:integer -c
When installing plugins, use the -x option to make it an svn:external
script/plugin install -x robot_cow
Source
has_many :through
Has Many associations can be configured with the :through option to use an explicit join model to retrieve the data. This operates similarly to a has_and_belongs_to_many association. The advantage is that you’re able to add validations, callbacks, and extra attributes on the join model. Consider the following schema:
class Author < ActiveRecord::Base
has_many :authorships
has_many :books, :through => :authorships
end
class Authorship < ActiveRecord::Base
belongs_to :author
belongs_to :book
end
@author = Author.find :first
@author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to.
@author.books # selects all books by using the Authorship join model
Sources
- Association Join Models (search for “Association Join Models”)
- Through Associations
Using SQLite in memory mode for Rails testing
Watching the latest PeepCode at about the 15:00 mark, he mentions using SQLite in memory mode for your testing database. Here’s what you put in your config/database.yml:
test:
adapter: sqlite3
database: ":memory:"
verbosity: silent
Run these commands:
$ script/plugin install memory_test_fix (use `--force` if you have any problems)
$ rake db:migrate
$ rake
Then you’re ready to go.
Sources:
See also how to set up SQLite for Rails
Rails Migration Data Types
Is this all of them?
:integer
:float
:datetime
:date
:timestamp
:time
:text
:string
:binary
:boolean
Found this:
Valid column types are integer, float, datetime, date, timestamp, time, text, string, binary, and boolean. Valid column options are limit, null (i.e. ” :null => false” implies NOT NULL), and default (to specify default values).
Why is this hard to find? Google search for “rails migration data types” isn’t that good.
And what’s the difference between datetime and timestamp? Or binary and boolean? Any database gurus read this?
Sources
Changing the name of an app’s cookie in Rails
While running Tracks and another app on my localhost, I realized that every time I did something on one, it would log me out of the other. Overwriting each other’s cookies!
Add this line to your config/environment.rb:
ActionController::Base.session_options[:session_key] = ‘yourappnamehere_session_id’
Then restart the app. All better now.
Using MySQL for storing Rails sessions
$ rake db:sessions:create
$ rake db:migrate
Possibly use -c on the first command to add the migration file to SVN?
Uncomment this line in your config/environments.rb:
config.action_controller.session_store = :active_record_store
Then restart your app.
Doing this is supposed to be more better than the default of using the file system.
Rails on DreamHost
Follow instructions carefully: Yet Another Guide to Installing Mephisto on Dreamhost
I had some trouble getting this to work, but I think it ended up being my own fault for not following the instructions to the letter. I’m going to have to try installing another app and see if it works again.
Note: when this guide mentions gem_name, don’t include .gem in the command. That is all.
Basic CRUD for Nested Elements using RESTful Rails
Continuing from where we left off…
(This all assumes you’ve set your app up using script/generate scaffold_resource with all the bells and whistles of spelling out your table columns in the command line.)
Make sure you’ve got your model relationships set up right:
# app/models/manufacturer.rb
has_many :appliances
# app/models/appliance.rb
belongs_to :manufacturer
Set up your nested routes:
map.resources :manufacturers do |manufacturers|
manufacturers.resources :appliances
end
In the controller for the dependent item, at the top of the file:
# app/controllers/appliances_controller.rb
before_filter :load_manufacturers
Then at the bottom of the same file:
private
def load_manufacturers
@manufacturer = manufacturer.find(params[:manufacturer_id])
end
Then back at the top of that file, for the index action:
@appliances = @manufacturer.appliances.find(:all)
Now for the views. To get started: in app/views/appliances/index.rhtml you should make sure that calls to appliance_path get the manufacturer id passed to them:
<%= link_to 'Show', appliance_path(@manufacturer, appliance) %>
In edit.rhtml and new.rhtml (or your _form.rhtml partial), you can remove the part of the form that lets you specify what manufacturer you want within the new/edit appliance form. You’ll get that from the params[:manufacturer_id] anyway. In the edit template, you’ll need to change the form a little bit for it to work:
# app/views/appliances/edit.rhtml
<% form_for(:appliance, :url => appliance_path(@manufacturer, @appliance), :html => { :method => :put }) do |f| %>
Notice we have to specifically specify the @manufacturer. Now back to the appliances controller:
def create
@appliance = appliance.new(params[:appliance])
@appliance.manufacturer_id = params[:manufacturer_id]
respond_to do |format|
if @appliance.save
flash[:notice] = ‘Appliance was successfully created.’
format.html { redirect_to appliance_url(@appliance.manufacturer_id, @appliance) }
…
It’s not smart enough to know that it needs the manufacturer_id param that’s just sitting there in the URL waiting to be used for something. Just about anywhere you need the appliance_url(), you have to specify the manufacturer_id. Whether it’s a param, or if it’s already sitting in the item you’re using:
# app/controllers/appliances_controller.rb
def update
...
if @appliance.update_attributes(params[:appliance])
format.html { redirect_to appliance_url(@appliance.manufacturer_id, @appliance) }
…
Hope that helps. It’s simple, right? ;)
Thanks again to PeepCode!