欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

rails 笔记

程序员文章站 2022-07-15 20:07:41
...
启动项目:

ruby script/server -e development(默认)
ruby script/server -e test
ruby script/server -e production

在编写ruby代码时,如果要引用另一个文件中的类和模块,需要使用require关键字,但是当我们在rails中引用另一个文件中的类和模块时,rails会自动把类名称根据命名约定改为文件名,然后在同一目录下加载该文件。


按模块组织控制器:

ruby script/generate controller Admin::Book action1 action2
admin模块下的book_controller控制器


Rails给Enumerable类扩展的方法
1》 group_by: 将一个对象集合分组,针对每个对象调用块,然后根据代码块的返回值作为分组的键,值是所有拥有同一个键的对象组成的数组。
eg:
User.all.group_by{|user| user.sex}
User.all.group_by(&:name)

2》 sum: 对集合进行加总,把每个元素传递给一个代码块,并对代码块返回的值进行累加。

User.all.sum(&:id) 返回所有user对象的id的和

3》 in_groups_of(arg1, arg2)  将某一个数组分为子元素由arg1个元素组合的数组元素组成的数组,出现无法填充的值由arg2填补。
eg:
[1,2,3,4,5].in_groups_of(2,"blank")     =>     
[[1,2],[3,4],[5,"blank"]]

字符串扩展
str[0] 第一个字符的Ascill码。
str[2..3] 返回字符串的第三个字符开始的3个字符组成的字符串。
str.at(0) 第一个字符
str.to(4) 前5个字符组成的字符串
str.from(4) 最后5个字符组成的字符串
str.first
str.last
str.starts_with?(字符串)
str.ends_with?(字符串)
str.each_char{|char| char.upcase}
str.pluralize 复数形式
str.singularize  单数形式
str.humanize
str.titleize


对数值的扩展:

figure.ordinalize   返回数字的序数形式

figure.bytes、kilobytes、megabytes、gigabytes、terabytes、
perabytes、exabyte  数据大小

figure.seconds、minutes、hours、days、weeks、fortnights、months、years  时间

注意:  ago、 until、 from_now、 since
eg: 
1.day.ago
1.day.ago(Time.now)


时间和日期的扩展

now = Time.now
now.to_s(:short)、to_s(:db)、to_s(:long)、to_s(:rfc822)
now.ago(2.days)、since(2.days)
change(:hour => 12)  改变日期的hour为12
advance(:hour => 12)  推迟日期的12hour
to_date、to_time
at_beginning_of_week、at_beginning_of_month、at_beginning_of_quarter(季)、at_beginning_of_year

ruby符号的扩展:
posts.group_by{|post| post.author_id}
posts.group_by(&:author_id)


with_options的使用:
Rails里有些方法使用一个Hash作为最后一个可选的参数,如果对多个方法有同样的选项,我们可以使用with_options来减少冗余:

eg:
with_options :if => :should_validate_password? do |user| 
  user.validates_presence_of :password 
  user.validates_confirmation_for :password 
  user.validates_format_of :password, :with => /^[^\s]+$/
end


迁移任务:
create_table  
:force => true  如果表存在,强制删除,然后再创建表
:temporary => true  创建一张临时表,程序与数据库断开链接,则表被删除。
:options => "xxxx"  指定针对于底层数据库的选项,这些选项会被加到create table语句的后面
:primary_key 主键
:id => false  没有主键的表

如果迁移任务 提供的方法 不够满足你 的需要,也 可以使用数 据库专有的 功能:使用execute() 方法就可以运行原生 SQL 语句。例如:给表加上外键

class CreateLineItems < ActiveRecord::Migration
    def self.up
      create_table :line_items do |t|
        t.column :product_id, :integer
        t.columnrails 笔记
            
    
    博客分类: rails语法 RailsActiveRecordRubySQLSQL Server rder_id,     :integer
      end
      execute "alter table line_items
          add constraint fk_line_item_products
          foreign key (product_id) references products(id)"
    end

     def self.down
      drop_table :line_items
     end
end


ActiveRecord::Base

column_names  属性组成的数组

columns_hash["属性名称"]  属性名称信息

属性_before_type_cast  读取属性时,ActiveRecod会尽量将得到的值转型成适当的ruby类型,如果我们希望的到属性的原始值,可以在属性名称后面加上before_type_cast。
eg:User.first.created_at    =>   2010-06-24 09:41:17

连接数据库:  ActiveRecord::Base.establish_connection(:adapter => "mysql", :host => "localhost", :database => "rails", :username => "root", :password => "1234")


防止恶意注入:

1> 问号占位符:   User.find(:all, :conditions => ["id > ?", 3]
2> 命名占位符:   User.find(:all, :conditions => ["id > :id", {:id => 3}])
注意:
命名占位符的语句可以转换为
User.find(:all, :conditions => ["id > :id", params[:user]])

获取字段统计信息:
average: 
maximum:
minimum:
sum  :
count  :

以上方法的参数: 
:conditions、:joins、:limit、:order、:having、:select、 :distinct

eg:
Order.maximum :amount, :group => "state", :limit => 3,rails 笔记
            
    
    博客分类: rails语法 RailsActiveRecordRubySQLSQL Server rder => "max(amount) desc"
拥有订单最大的三个州


更新操作:
update_attribute、update_attributes、update、update_all

创建操作:
create、create!、save、save!

删除数据:
delete、delete_all、destroy、destroy_all
delete绕过了ActiveRecord的回调和验证,destory没有绕过回调和验证


序列化数据:

serialize :属性
序列化的属性可以直接存入Array和hash类型的数据,也可以直接读出来使用
缺点:
ruby应用之外的应用访问序列化的数据时,除非它能够理解yaml格式,否则无法获取这个字段的信息。

弥补这种缺点的方式是用对象聚合的方式来实现类似的效果


聚合/组合:

聚合可以把一个或多个属性封装为一个类,然后这个类里可以添加操作属性的方法,这样我们就可以实现序列化所要实现的目的了,而且可以避免序列化的缺点。

composed_of :attr_name, :class_name => 类名称, :mapping => [字段与属性组成的数组]

eg:
class Xingxi < ActiveRecord::Base
  composed_of :inf, :class_name => "Inf", :mapping => [[:name, :name], [:phone, :phone]]
end

class Inf
    attr_reader :name, :phone

    def initialize(name, phone)
        @name = name
        @phone = phone
    end

    def to_s
      [@name, @phone].compact.join(" ")
    end
end

inf = Inf.new("zcy",  "12344454")

Xingxi.create(:inf => inf)

注意:
教程上指出  :class_name对应的“类名称”可以是类常量,也可以是包含类常量的字符串,但实际上只能是包含类常量的字符串,如果类名恰好是属性名的混合大写形式,那么class_name可以省略,但是实际上不可以,包括:mapping也不可以。


关联:
class Line < ActiveRecord::Base
  belongs_to :product
end
belongs_to :product  会产生以下方法

1>:product(force_reload=false) 返回关联的product对象,默认情况下product对象会被缓存,当force_reload=true时,将重新查询数据库。

2>:product=: line对象和product对象关联起来,将line记录的外键值设为product的主键值,如果product没有保存,line保存的时候会保存product,包括外键。

3>:build_product(attributes={}) 新建一个product对象,用指定的属性对其初始化,相当于product=Product.new(attributes)。

4>:build_create(attributes={}) 创建一个product对象,与line关联,保存product对象。

order:  has_one中也有order,主要用于例如最后一个***,此时便可以用order指定排序。
:dependent   :destroy(true)、:nullify、 false
    :destroy   删除记录的同时也删除子记录
    :nullify   删除记录的同时删除子记录的外键
    false      只删除记录


has_many :lines
class Product < ActiveRecord::Base
  has_many :lines
end
has_many :lines  会产生以下方法

lines(force_reload=false)  同上
lines.build(attributes = {})
lines.create(attributes = {})
lines << line  将当前line对象添加到lines对象数组里
lines.push(line对象) line对象添加到lines
lines.delete(line,...) 删除一个或多个line对象,如果关联为:destroy => :destroy,子对象被删除,否则只是删除子对象的外键,打断与父对象的关联。
lines.delete_all  调用所有子对象的delete方法
lines.destroy_all   调用所有子对象的destroy方法
lines.clear  和delete一样,不同的是clear针对的是所有的子对象。
lines.find(options)
lines.count(options)
lines.size
lines.length  强制加载所有子对象,返回对象的集合。
lines.empty?
lines.replace(line对象数组)  line对象数组替换原先的lines
lines.sum(options) 不便利内存中的子对象集合,直接在数据库端操作
lines.uniq  返回一个数组,包含所有具备独立id的子对象



1> finder_sql: 重新定义了统计子记录的sql语句
   counter_sql: 重新定义了统计子记录的数目
注意: 如果指定了finder_sql而没有指定counter_sql,finder_sql中的子句会被替换为select count(*),然后记录子记录的数量。
eg:
has_manyrails 笔记
            
    
    博客分类: rails语法 RailsActiveRecordRubySQLSQL Server ingxis, :finder_sql => "select x.* from xingxis x, infos i where x.info_id = i.id and x.id > 4"

作用: 当:conditions无法满足时,:finder_sql显的非常重要。

:order : 以特定的顺序排列
:conditions : 返回符合条件的子记录
:dependent   :destroy、:nullify、 false
    :destroy   删除记录的同时也删除子记录
    :nullify   删除记录的同时删除子记录的外键
    false      只删除记录


多对多的关联有两种
1: 利用默认的关联表
2:自己创建关联表,利用关联中的:through

:through   告诉rails通过guanlians表来导航关联
:source  用来指定关联在那个属性上
:uniq => true  去掉重复的对象 等同于 :select => "distinct books.*"

eg:
class Kind < ActiveRecord::Base
    has_many :guanlians
    has_many :readers, :through => :guanlians, :source => :book
end

注意:

has_many :reader1s,:conditions => "guanlians.cishu > 0"
当使用conditions不能很好的表达时,无法提供参数,可以考虑以下格式,而且当同样的方法被多次调用时,可以将方法写在模块中,然后在关联中:extend => "模块名称" 来调用。
has_many :readers do
    def reader(limit = 3)
        find(:all, :limit => limit)
    end
end

单表继承: 
优点:  这样做的好处是提高读取表的速度,因为没有关联,只有一个表。
缺点:  当各个子类的相似的地方很少的时候,会导致表中有很多属性,这样处理这个问题的方法是用多态关联。

多态关联:

types表中的多态外键如果是duotai,那么表的属性是duotai_id, duotai_type,一个记录键值,一个记录类名。

class Article < ActiveRecord::Base
    has_one :type, :as => :duotai
end

class Image < ActiveRecord::Base
    has_one :type, :as => :duotai
end

class Type < ActiveRecord::Base
    belongs_to :duotai, :polymorphic => true
end


自引用的连接:

class Employee < ActiveRecord::Base
  belongs_to :boss, :class_name => "Employee", :foreign_key => :employee_id
end

预先读取子记录
以下实例如果没有:include => :people, infos为n, 那么他将执行2n+1次,如果指定了:include,将预加载与info有关的people记录,此时将提高效率,但是如果预加载了数据,但没有用这些数据,反而会降低效率。
Benchmark.bm() do |x|
    x.report{
        infos = Info.find(:all, :include => :people)
        infos.each do |info|
            info.people.name
        end
    }
end

如果一个对象刚刚创建出来,还没有与数据库记录建立映射,我们称它为新对象(new records)。调用new_records?

模型验证:
validate、 validate_on_create、 validate_on_update

ActiveRecord::Errors

[]  info.errors[:email]
on  info.errors.on(:email)
add(:属性, 信息)
size、length、count
each、each_error  迭代错误属性和错误属性对应的信息
each_full  迭代错误信息
full_messages  错误信息组成的数组
invalid?(属性)  如果属性无效,则返回true
to_xml
empty?
ActiveRecord::Errors.default_error_messages  这个返回所有的默认信息,如果修改默认信息的话,可以从这里修改。


回调:

创建方式
1:直接在回调中写代码。
2:声明回调处理器,处理器可以是一个代码块也可以是一个方法,如果用方法作为一个处理器,应该被声明为private或protected。
eg
def before_save
  ...
end

before_save :check

private
def check
end

注意:以下方法将跳过回调
    * decrement
    * decrement_counter
    * delete
    * delete_all
    * find_by_sql
    * increment
    * increment_counter
    * toggle
    * update_all
    * update_counters



ActiveRecord::Base

column_names:  所有列名组成的数组
columns:  所有包含列信息的对象组成的数组。
columns_hash:   列名与列对象组成的hash数组。

实例方法:
attributes:  所有属性和属性值组成的hash数组。
attributes=
attribute_names:  所有属性组成的数组。
attribute_present?(属性名称) 如果属性名称存在,则返回true,反之亦然。



事务: 要么全部执行,要么全部不执行。

模型类.transaction do
end

begin ... rescue ...end

eg:
class Info < ActiveRecord::Base
  def validate
    errors.add(:age, "age is not less than 0") if age < 0
  end

  def jian(i)
    self.money = self.money - i
    self.save!
  end
end


info = Info.create!(:money => 100)

begin
Info.transaction do; info.jian(200); end
rescue
end

puts info.money   =》 -100

该实例中要求money不能小于0,而我们也做到了,表中的数据不会被改,但是info.money 返回的值是-100,模型对象的值被该变了,这是因为ActiveRecord没有跟综对象在事务前后的状态,我们可以指定事务跟踪哪些模型对象。
Info.transaction(info) do; .... end,此时输出的值就是100了。


路由:
map.connect 重要参数
:requirements => {:name => /regexp/}  要求url中特定的组成部分与指定的正则表达式一一匹配。
:defaults => {:name => "value", ...}  设定各组成部分的默认值
:conditions => {:name => /regexp/orstring,...}  设定路由的条件
:name => value  设定:name参数的默认值

eg:
map.connect 'infos/:year', :controller => "infos", :action => "hello", :defaults => {:year => 2008},:requirements => {:year => /(19|20)\d\d/}, :conditions => {:method => :get}

注意:
map.connect "*aa", :controller => "", :action => ""
符合任何的url格式,但是一定要注意的是要放在最后,否则其他的路由都无法匹配了。


有名路由
map.hello "hello/:id", :controller => "infos", :action => "index"

1>  hello_url(:id => 1)或hello_url :controller => "infos", :action => "index"
可以访问这个url。

注意: 以上url可以用path替代。

2>  地址栏中可以输入hello访问这个url。


资源路由:

map.resources :articles, :collection => {:recent => :get}, :member => {:release => :put}, :new => {:hello => :get}

增加以下规则:
recent_articles_path
release_article_path(:id => 1)
hello_new_article_path




map.resources :articles do |article|
  article.resources :comments
end

articles/99/comments/4


控制器环境(可以在action中直接引用)

controller_name:  controller名称
action_name:  action名称
session: session
cookies: cookie
params: 存放着参数的hash对象
rsponse
request: 进入控制器的请求对象,包含属性。
  domain: 请求地址域名部分的最后两端。
  remote_ip: 客户端的ip地址。
  env: 返回请求的环境。
  get?、post?、put?、delete?、head?
  method:  返回客户端访问所使用的请求方法。
  xhr?或xml_http_request?  如果请求来自AJAX的辅助方法,则返回true,否则返回false。



控制器应答:
1:渲染一个模板,最常见的(.html、 .rxml、 .rjs)。
2:返回一个字符串给浏览器,主要用于发送错误提示。
3:发送html以外的数据,这种方式通常用于提供下载。


控制器每次只响应一个请求:
render、 redirect_to、 send_xxx
1> render :action
2> render :template
3> render :file
4> render :partial  调用局部模板
:object 指定传递给局部模板的对象。
5> renderrails 笔记
            
    
    博客分类: rails语法 RailsActiveRecordRubySQLSQL Server ml
6> render :nothing
7> render :inline
8> render :text
9> render(:update) do |page| ... end
重要参数:
:locals => {},指定模板要使用的局部变量。
:layout => false|nil|true|模板名称。


render_to_string 可以当作render使用,不过它不会跳转,只会把整个的内容作为字符串返回。


method_missing:调用指定的action名称无效时,method_missing会渲染一个内联的模板,将action的名称和请求参数显示出来。


eg:
  def method_missing(name, *args)
    render(:inline => %{<h2> Unknown action: #{name}</h2>
    Here are the request parameters:<br/>
    <%= debug(params) %>})
  end




send_data(data, options)  发送一个数据流给客户端。
参数:
:filename、 disposition(inline|attachment)、status、type

send_file(path, options)  发送一个文件给客户端
参数:
:filename、 :disposition、 :status、 :type、 buffer_size、 stream


重定向:
redirect_to(:action => "")
redirect_to(path)
redirect_to(:back)  返回上一页,注意:如果redirect_to(:back)写在了index的action中,并且访问index的时候能够直接运行redirect_to(:back),则不能直接访问index的action,因为他会跳转上一页,但是没有上一页。


过滤器:
prepend_before_filter
before_filter、append_before_filter
prepend_after_filter
after_filter、append_before_filter

参数:
:only、 :except

定义过滤器的方式:
1:
before_filter do
  ...
end

2:
before_filter :hello,rails 笔记
            
    
    博客分类: rails语法 RailsActiveRecordRubySQLSQL Server nly => [:show, :index]


skip_filter、 skip_before_filter、skip_after_filter
参数:
:only、 :except


缓存:

片段缓存、 页面缓存、 action缓存
caches_page、 caches_action、 cache do .... end

默认配置下,cache只有在产品环境下才生效,如果要在开发环境下生效,要配置以下信息中的一条。(config/environments/development.rb)
ActionController::Base.perform_caching = true|false
config.action_controller.perform_caching = true

解除缓存:
expire_action、 expire_page、 expire_fragment :controller => "...", :action => "..."

1》默认:缓存片段的名字取决于渲染该页面的控制器名称和action名称,所以使用expire_fragment指定控制器名称和action名称来是对应的片段缓存失效。
2》指定缓存名称(等同于url_for的参数)


缓存存储机制的全局设置(environment.rb设置):
缓存目录:
config.action_controller.page_cache_directory = RAILS_ROOT + "/public/caches"
缓存类型:
config.action_controller.page_cache_extension = ".html"


缺点:导致大量的数据从网络驱动器传输到某一台具体的web服务器,然后将这些数据发送给用户,所以,如果在高吐量的网站中使用这种存储机制,服务器之间的网络宽带应该非常宽。

缓存存储体系只对action缓存和片段有效,全页面缓存必须以文件的形式放在public目录下。

页面缓存是最快速的一种缓存应用。那么应该在什么时候使用他呢?
1、对于所有用户都相同的页面
2、公开的页面,没有用户认证的页面

缓存分页:
因为页面缓存的时候会忽略掉像/blog /list?page=2这样的参数,所以你需要使用/blog/list/2这样的地址形式,而原来我们使用的是id保存参数值,现在我们需要用 page来保存参数值。
下面我们修改 /config/routes.rb文件

map.connect 'blog/list/:page',
    :controller => 'blog',
    :action => 'list',
    :requirements => { :page => /\d+/},
    :page => nil

使用了新的routes定义,我们的连接也应该改成

<%= link_to "Next Page", :controller => 'blog', :action => 'list', :page => 2 %>

最终的连接结果是"/blog/list/2",当我们点这个连接的时候,后台会处理两件事情
1、应用将2放入page这个参数中,而不是原来id这个参数
2、缓存将生成 /public/blog/list/2.html 这个页面

所以,缓存分页,就要将页面参数变成页面的一部分,而不要使用地址参数的形式,他是会被忽略的。


解决危险链接的方式:
1:使用表单和按钮(button_to)
2:使用确认页面


link_to、link_to_if、link_to_unless、button_to
stylesheet_link_tag
javascript_include_tag:   假设文件在public/javascripts目录

对象调用属性:
eg: info.name 或 info["name"]

form_for、 form_tag

form_for(:info, @info, :url => {:action => "create"}, :html => {:method => "post"}
:info   告诉rails正在操作哪个模型类的对象
@info   通过哪个实例变量获得该对象
:url    访问的action地址
:html   定义访问的方法,可以定义:multipart => true,上传。


select标签:
1>collection_select(:post, :author_id, Author.all, :id, :name_with_initial, {:prompt => true})

2>select、select_tag "people", "<option>David</option>"

3>options_from_collection_for_select(@people, 'id', 'name')

4>options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40")

子表单:
<% fields_for :name, @info.name do |field| %>
  Name: <%= field.text_field :name %>
<% end %>


卸载layout页面中:

<% content_for :head do %>
  <ul><li>a</li><li>b</li></ul>
<% end %>

<%= yield :head %>



发送邮件:

config.action_mailer.delivery_method = :smtp|:sendmail|:test

开发环境下默认的设置是:smtp。
:smtp、:sendmail 可以让ActionMailer发送邮件。
:test 可以用于单元测试和功能测试,电子邮件不会发送出去,而是被放入一个数组。

禁止开发环境下发送邮件:
config/environments/development.rb中设置config.action_mailer.delivery_method = :test

config.action_mailer.perform_deliveries = true|false
perform_deliveries为true,邮件被正常发送,否则不发送,用于测试。

config.action_mailer.raise_delivery_errors = true|false
设置邮件发送过程中的异常是否抛还给应用程序。false为忽略,true为抛还。

config.action_mailer.default_charset = "utf-8"
设置发送邮件的字符集。

ActionMailer::Base.smtp_settings = {
    :address => "smtp.163.com",:port => 25,:domain => ".com",    :authentication => :login,:user_name => "zhangcaiyan0123@163.com",:password => "zhangcaiyan",}
设置smtp服务器(其中domain是域名称)


ruby script/generate mailer OrderMailer confirm sent
模型中定义方法:
  def confirm(sent_at = Time.now)
    subject    '标题'
    recipients "zhangcaiyanbeyond@gmail.com"
    from       'zhangcaiyan0123@163.com'
    sent_on    sent_at
    body       "邮件正文"
  end

bcc          暗送
cc           抄送
charset        默认为smtp_settings中的default_charset属性
subject        标题
from        发件人的邮箱
recipients     收件人的邮箱
body        正文
send_on     发送时间
headers        指定邮件的头信息
attachment(上传插件) :filename => 文件名称, :body => 文件内容(file.read), :content_type => "内容类型"


OrderMailer.deliver_confirm   发送邮件

email = OrderMailer.create_confirm    创建邮件对象(TMail::Mail对象)
OrderMailer.deliver(email)

注意:  OrderMailer是模型类,create_confirm中的create是表示要创建对象,confirm是表示模型类中的方法,deliver表示要发送邮件。



保护rails应用:

防御sql注入攻击:
eg:这个实例就是恶意注入的例子,其中1为true,他会查处表中的所有数据。
Core::User.find(:all, :conditions => "id > '' or 1")

防止恶意注入:
绝对不要用ruby的#{...}机制直接把字符串插入到sql语句中,而应该用Rails提供的变量绑定。
eg:
Core::User.find(:all, :conditions => ["id > ?", 3])
Core::User.find(:all, :conditions => ["id > :id", {:id => 3}])



用参数直接创建记录:
User.create(params[:user])

为了防止用户模拟一些属性提交,我们可以将某些属性保护起来。

attr_protected  :属性1, :属性2  列出被保护的属性
attr_accessible :属性1, :属性2  列出允许自动赋值的属性,也就是说除此之外的都是被保护的属性

被保护的属性也就是不能通过create(params[:user])直接保存,而是需要通过赋值才可以。eg:
user = User.new
user.role = params[:role]
user.save


不要相信ID参数:
当我们通过id查找出数据,然后对数据进行操作时,我们要注意某些情况:例如当我们浏览(/show/id)某个用户的数据时,可以利用url浏览其他用户的数据,为了防止这样的事发生,可以这样:
eg:
1》 order = Order.find(params[:id], :conditions => ["user_id = ?", user_id])
2》 order = @user.orders.find(id)
3》 order = @user.orders.find(id).destroy


防御XSS攻击:

攻击者把自己编写的javascript脚本放进网页,来获得他们想要的cookie,我们可以通过rails提供的h(string)辅助方法(实际上是html_escape()方法的别名)


生成rails项目的HTML文档
rake doc:app


ActiveRecord::Errors.default_error_messages = hash
修改默认错误显示信息



named_scope的使用:

named_scope :quanbu, :conditions => ["name=zcy"]
named_scoperails 笔记
            
    
    博客分类: rails语法 RailsActiveRecordRubySQLSQL Server ianzhi, :lambda{|limit|{:limit = limit}}

Shili.quanbu.xianzhi(3)


显示错误页面:  当指定的异常发生时,将显示特定的页面,这个最好放到application_controller中

rescue_from  异常, :with => :action

eg:
rescue_from Exception, :with => :error

def error
  render :file => "novel/infos/error", :layout => "novel"
end

对于boolean类型的数据,应该省略前面的is_,ActiveRecord会自动加个?号,映射成actived? ,不是boolean型的数据也会也会扩展?




_form下的共享表单,区间的情况

1:map.namespace :doctor do |doctor|
    doctor.resources :patients
end
["doctor", @patient ]

2:map.resources :doctor do |doctor|
    doctor.resources :patients
end
[@doctor, @patient ]