Rails 3: Difference between revisions

From Wiki
Jump to navigation Jump to search
Blanked the page
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
== Application Setup ==
* create project with
<pre>
rails new my_project
rails -d mysql new my_project  # if you don't want the default sqlite3
</pre>
* add gem dependencies to <code>Gemfile</code> at the root level
* update <code>config/application.rb</code> to load needed dependencies and update defaults
* double-check <code>/config/initializers</code> and <code>/config/environments</code>
* edit <code>config/database.yml</code> to connect to your database


=== Notes ===
Files in <code>lib/</code> are not automatically loaded, so you need to <code>require</code> them.
In <code>config/environments/development.rb</code>, set
<pre>
config.action_mailer.perform_deliveries = false
</pre>
No delivery attempt is performed, but you can still see the mail in the log file to check it looks good
== Database Setup ==
* create database with
<pre>
rake db:create
</pre>
=== Create a table and its controller ===
<pre>
rails generate model Article
</pre>
Edit <code>db/migrate/20100223220648_create_articles.rb</code> to look like this:
<source lang="ruby">
class CreateArticles < ActiveRecord::Migration
    def self.up
        create_table :articles do |t|
            t.string :title
            t.text :body
            t.datetime :published_at
            t.timestamps
        end
    end
    def self.down
        drop_table :articles
    end
end
</source>
To create/update the table:
<pre>
rake db:migrate
</pre>
To generate the controller:
<pre>
rails generate controller articles
</pre>
=== Make a scaffold ===
To make a scaffold for the table to allow easy create/update/delete in development:
<pre>
rails generate scaffold Article title:string body:text published_at:datetime --skip-migration
</pre>
WARNING: As you develop your application, you will eventually replace most or even all of the code that the scaffold generates in the controller.
=== Update table and scaffold ===
To modify the table, generate a custom migration:
<pre>
rails generate migration add_excerpt_and_location_to_articles excerpt:string location:string
</pre>
creates this migration file <code>db/migrate/20100223232337_add_excerpt_and_location_to_articles.rb</code>:
<source lang="ruby">
class AddExcerptAndLocationToArticles < ActiveRecord::Migration
    def self.up
        add_column :articles, :excerpt, :string
        add_column :articles, :location, :string
    end
    def self.down
        remove_column :articles,
        :excerpt remove_column :articles, :location
    end
end
</source>
Run <code>rake db:migrate</code> again to update the database.
Now update the scaffold:
<pre>
rails generate scaffold Article title:string location:string excerpt:string body:text published_at:datetime --skip-migration
</pre>
=== Add validations to the model ===
Edit <code>app/models/article.rb</code>:
<source lang="ruby">
class Article < ActiveRecord::Base
    validates :title, :presence => true
    validates :body, :presence => true
end
</source>
== Other rails commands ==
<pre>
rails console
rails dbconsole
rails server
rails runner
</pre>
== Routing ==
Configured in <code>config/routes.rb</code>
<pre>
match 'products/:id' => 'products#show'
</pre>
The url <code><nowiki>http://localhost:3000/products/8</nowiki></code> will be mapped to the <code>show</code> action of the <code>products</code> controller with <code>params[:id]</code> set to 8
To create a link to this route (old way):
<pre>
link_to "Products", :controller => "products", :action => "show", :id => 1
</pre>
To restrict the HTTP method, use get or post instead of match:
<pre>
get 'products/:id' => 'products#show'
</pre>
To redirect:
<pre>
match "/foo", :to => redirect("/bar")
</pre>
== Logging ==
Use these in models, views, controllers to send timestamped messages to the log.
<source lang="ruby">
logger.debug "debug message"
logger.info "info message"
logger.warn "something bad"
logger.error "something broke"
logger.fatal "application dead"
</source>
== Active Record ==
=== Create and Save ===
<source lang="ruby">
article = Article.new  # make an empty object
article.title = "My Title"  # add attributes
article.author = "Herman"
article.save  # save to database
</source>
<source lang="ruby">
article.create(:title => "My Title", :author => "Herman")  # make, set attributes, and save
</source>
<source lang="ruby">
article.new_record?  # new means not saved to database
</source>
=== Find ===
<source lang="ruby">
Article.find(3)                # look for id = 3
Article.first                  # same as Article.find(:first), uses "LIMIT 1" in SQL, so may not be id = 1
Article.last                  # same as Article.find(:last)
Article.all                    # same as Article.find(:all)
Article.where(:title => 'RailsConf').first  # chaining
Article.find_by_title('RailsConf')  # dynamic finder
</source>
=== Update ===
<source lang="ruby">
article = Article.first
article.title = "Rails 3 is great"
article.published_at = Time.now
article.save
</source>
<source lang="ruby">
article = Article.first
article.update_attributes(:title => "RailsConf2010", :published_at => 1.day.ago)  # saves too
</source>
=== Delete ===
<source lang="ruby">
Article.find(3).destroy  # find, then destroy
Article.destroy(3)      # same thing
Article.delete(3)        # delete directly from database with no object callbacks
Article.delete_all("published_at < '2011-01-01'")  # conditional
</source>
=== Validation and Errors ===
<source lang="ruby">
class Article< ActiveRecord::Base
    validates :title, :presence => true
    validates :body, :presence => true
end
</source>
<source lang="ruby">
article = Article.new
article.errors.any?          # false
article.save                  # returns false because of validation
article.errors.full_messages  # ["Title can't be blank", "Body can't be blank"]
article.errors.on(:title)    # "can't be blank"
article.valid?                # false
</source>
=== Associations ===
==== One-to-one ====
<source lang="ruby">
class User < ActiveRecord::Base
    has_one :profile          # assumes User.profile_id column
end                            # creates User.profile method
-------------------------------
class Profile < ActiveRecord::Base
    belongs_to :user          # assumes Profile.user_id column
end                            # creates Profile.user method
</source>
==== One-to-many ====
<source lang="ruby">
class Message < ActiveRecord::Base
    has_many :attachments        # creates Message.attachments method
end
-------------------------------
class Attachment < ActiveRecord::Base
    belongs_to :message          # assumes Attachment.message_id column
end                              # creates Attachment.message method
</source>

Latest revision as of 21:02, 28 June 2011