zl程序教程

您现在的位置是:首页 >  其它

当前栏目

[Rails Level 2] Models

level Models Rails
2023-09-14 09:00:56 时间

SCOPES I

Write a scope on the Tweet model called recent which returns the 4 most recent tweets. Hint: You'll need an order AND a limit scope.

#schema.rb
ActiveRecord::Schema.define(:version => 20110814152905) do
 
  create_table "tweets", :force => true do |t|
    t.string "message"
    t.string "location", :limit => 30
    t.boolean "show_location", :default => false
    t.integer "zombie_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
end

Answer:

class Tweet < ActiveRecord::Base
    scope :recent, order('created_at DESC').limit(4)
end

 

SCOPES II

Write another scope called graveyard which only shows tweets where the show_location column is true and the location is "graveyard".

class Tweet < ActiveRecord::Base
  scope :recent, order('created_at desc').limit(4) 
  scope :graveyard, where({show_location: true, location: "graveyard"})
end

 

USING SCOPES

In this controller action create an instance variable called @graveyard_tweets which uses both of the two scopes recent and graveyard together.

#tweet.rb
class Tweet < ActiveRecord::Base
  scope :recent, order('created_at desc').limit(4)
  scope :graveyard, where(show_location: true, location: "graveyard")
end

Answer:

class TweetsController < ApplicationController
  def index
    @tweets = Tweet.all
    @graveyard_tweets = Tweet.recent.graveyard
  end
end

 

BEFORE SAVE

Create a before_save callback that checks to see if a tweet has a location, if it does have a location then set show_location to true.

Tip: You can check to see if location exists with if self.location?

#schema.rb
ActiveRecord::Schema.define(:version => 20110814152905) do create_table "tweets", :force => true do |t| t.string "message" t.string "location", :limit => 30 t.boolean "show_location", :default => false t.integer "zombie_id" t.datetime "created_at" t.datetime "updated_at" end end

Answer:

class Tweet < ActiveRecord::Base
  before_save :check_location

  def check_location
     self.show_location = true if location
  end
end

 

CALLBACK LOGGING

Add callbacks so the appropriate log function is called after an update and destroy.

class Tweet < ActiveRecord::Base

  after_update :log_update
  after_destroy :log_destroy

  def log_update
    logger.info "Tweet #{id} updated"
  end

  def log_destroy
    logger.info "Tweet #{id} deleted"
  end
end

 

HAS ONE

Instead of storing location inside the Tweet model, let's instead break it out into a separate table (as you see below). In this case we want to define that a Tweet can have one Location, and a Locationbelongs to a Tweet. Fill out the models below accordingly.

ActiveRecord::Schema.define(:version => 20110814152905) do
 
  create_table "locations" do |t| 
    t.integer "name"
    t.integer "tweet_id"
  end
      
  create_table "tweets" do |t|
    t.string "message"
    t.boolean "show_location", :default => false
    t.integer "zombie_id"
        
    t.timestamps
  end
 
end

Answer:

class Tweet < ActiveRecord::Base
  has_one :location
end

class Location < ActiveRecord::Base
  belongs_to :tweet
end

 

FOREIGN KEY

OH NO! Our Database Admin turned into a Zombie and decided to rename the belongs_to field in our locations table tweeter_id instead of the intelligent default tweet_id. We're going to slay him and correct this, but in the meantime set the foreign_key on both relationships to tweeter_id. Also set the dependency so when a tweet is destroyed, the location is destroyed as well.

ActiveRecord::Schema.define(:version => 20110814152905) do
 
  create_table "locations" do |t| 
    t.integer "name"
    t.integer "tweeter_id" # BRAINS!!!
  end
      
  create_table "tweets" do |t|
    t.string "message"
    t.boolean "show_location", :default => false
    t.integer "zombie_id"
        
    t.timestamps
  end
 
end

Answer:

class Tweet < ActiveRecord::Base
  has_one :location, foreign_key: :tweeter_id, dependent: :destroy
end

class Location < ActiveRecord::Base
  belongs_to :tweet, foreign_key: :tweeter_id
end

 

INCLUDES

We're going to be iterating through many tweets and printing out their location. Refactor the controller code below to use the includes method.

class Tweet < ActiveRecord::Base
  has_one :location, dependent: :destroy
end
 
class Location < ActiveRecord::Base
  belongs_to :tweet
end

Answer:

class TweetsController < ApplicationController 
  def index
    @tweets = Tweet.includes('location').recent
  end
end

 

RELATIONSHIP MIGRATION

Tweet can belong to one or more Categories (e.g. eating flesh, walking dead, searching for brains). Write a migration that creates two tables, categories, and categorizations. Give categories one column named name of type string; and give categorizations two integer columns: tweet_id andcategory_id.

class AddTweetCategories < ActiveRecord::Migration
  def change
    create_table(:categories)  do |t|
      t.column :name, :string
    end  
    
    create_table(:categorizations) do |t|
      t.column :tweet_id, :integer
      t.column :category_id, :integer
    end
  end 
end

 

HAS MANY THROUGH

Now that we have our new tables, it's time to define the relationships between each of the models. Define the has_many through relationships in the Tweet & Category model and the belongs_torelationships in the Categorization model.

ActiveRecord::Schema.define(:version => 20110814152905) do
 
  create_table "categories" do |t|
    t.string "name" 
  end
      
  create_table "categorizations" do |t| 
    t.integer "tweet_id"
    t.integer "category_id"
  end
      
  create_table "tweets" do |t|
    t.string "message"
    t.string "location", :limit => 30
    t.boolean "show_location", :default => false
    t.integer "zombie_id"
        
    t.timestamps
  end
 
end

Answer:

class Tweet < ActiveRecord::Base
  has_many :categorizations
  has_many :categories, through: :categorizations
end

class Categorization < ActiveRecord::Base
  belongs_to :tweet
  belongs_to :category
end

class Category < ActiveRecord::Base
  has_many :categorizations
  has_many :tweets, through: :categorizations
end