[ROR] 必知必会知识点[持续总结中...]

一、Ruby语言本身

  • String 对象的is_digit?
    通过scan方法实现:
    3.0.1 :039 > '0108551'.scan(/\D/).empty?
     => true
    3.0.1 :040 > '0108551a'.scan(/\D/).empty?
     => false
    3.0.1 :041 >

     

  • require、load和include。
    require:形式为require 'active_support/concern'。 请求一个模块,需要不带扩展名的文件名,程序中多次requrie这个模块不会多次装载,ruby会使用内存中的缓存;
    load:形式为require 'active_support/concern.rb'。请求装载一个模块,需要带扩展名,每次执行到load,不管以前是否装载过,ruby都会再次读取此模块;
    include:形式为:include ActiveSupport::Concern。mixin一个模块,使用的是模块的名称而不是文件名,其实和前两个没啥关系,很多时候需要一起使用;

  • 查看一个类的方法。
    methods、public_methods、private_methods、instance_methods、public_instance_methods
    irb(main):025:0> Test2.instance_methods
    => [:m1, :to_json, :blank?, :as_json, :acts_like?, :deep_dup, :present?, :duplicable?, :with_options, :html_safe?, :in?, :presence_in, :dclone, :`, :to_yaml, :to_param, :to_query, :instance_values,
    :instance_variable_names, :presence, :pretty_print_cycle, :pretty_print_inspect, :pretty_print, :pretty_print_instance_variables, :require_dependency, :unloadable, :require_or_load,
    :load_dependency, :try, :try!, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_get, :instance_variables, :instance_variable_set,
    :protected_methods, :private_methods, :public_send, :method, :public_method, :singleton_method, :class_eval, :pretty_inspect, :define_singleton_method, :extend, :suppress_warnings, :to_enum,
    :enum_for, :<=>, :===, :=~, :!~, :eql?, :respond_to?, :gem, :freeze, :inspect, :object_id, :send, :to_s, :display, :class, :nil?, :hash, :dup, :singleton_class, :clone, :then, :itself,
    :yield_self, :untaint, :taint, :tainted?, :trust, :untrust, :untrusted?, :singleton_methods, :frozen?, :methods, :public_methods, :equal?, :!, :==, :instance_exec, :!=, :instance_eval,
    :__id__, :__send__]

      

    # 为了便于查看,可以排一下序
    irb(main):034:0> Test2.instance_methods.sort
    => [:!, :!=, :!~, :<=>, :==, :===, :=~, :__id__, :__send__, :`, :acts_like?, :as_json, :blank?, :class, :class_eval, :clone, :dclone, :deep_dup, :define_singleton_method, :display, :dup, 
    :duplicable?, :enum_for, :eql?, :equal?, :extend, :freeze, :frozen?, :gem, :hash, :html_safe?, :in?, :inspect, :instance_eval, :instance_exec, :instance_of?, :instance_values,
    :instance_variable_defined?, :instance_variable_get, :instance_variable_names, :instance_variable_set, :instance_variables, :is_a?, :itself, :kind_of?, :load_dependency, :m1, :method,
    :methods, :nil?, :object_id, :presence, :presence_in, :present?, :pretty_inspect, :pretty_print, :pretty_print_cycle, :pretty_print_inspect, :pretty_print_instance_variables, :private_methods,
    :protected_methods, :public_method, :public_methods, :public_send, :remove_instance_variable, :require_dependency, :require_or_load, :respond_to?, :send, :singleton_class, :singleton_method,
    :singleton_methods, :suppress_warnings, :taint, :tainted?, :tap, :then, :to_enum, :to_json, :to_param, :to_query, :to_s, :to_yaml, :trust, :try, :try!, :unloadable, :untaint, :untrust,
    :untrusted?, :with_options, :yield_self] irb(main):035:0>

     

  • YAML.load 替代JSON.parse
    ruby虽然内置了JSON,但是由于限制太严格(比如,不能有结尾逗号:{"a":1,"b":2,} ), 那是相当地不太好用,这里推荐使用YAML.load替代,那个谁用谁知道。

  • URI.url_encode没有了,但是我们还有 ERB::Util.url_encode

  • 如果项目的安全性没那么重要,我建议还是把config/master.key加入源码控制吧

  • Time.now.to_i 返回自1970-01-01 0:00:00以来的秒数(UTC), Time.at(刚才那个数) 转回时间, Time.at(0)就是1970-01-01 0:00:00

  • 在ApplicationController中添加
    before_action ->{ActiveStorage::Current.host = request.base_url}
    这样对于ActiveStorage的附件,就可以用.url来获取其访问地址了(console中不行,但是可以手工设置一下ActiveStorage::Current.host ='http://localhost:3000')
  • 'ActiveViewUtils'.tableize => "active_view_utils"
  • "active_view_utils".camelize => 'ActiveViewUtils'

二、UI视图(ActionView)相关

  •  AJAX访问(非get方法)错误引发错误“ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken)” , 在controller中添加下面命令,跳过校验
    skip_before_action :verify_authenticity_token

     如果不想跳过,则需要在ajax参数中添加这个key

    var pn=$('meta[name="csrf-param"').attr('content'),pv=$('meta[name="csrf-token"').attr('content');
    
    if(data instanceof FormData){
      data.append(pn,pv);
    }
    else{ data[pn] = pv; }

     

三、ActiveRecord 

  • 事务操作Transaction,使用ActiveRecord::Base.transaction开始事务,注意的是,内部数据库操作需要使用出错时引发例外的方法(多数以!结尾),这样才能触发事务回滚操作
    ActiveRecord::Base.transaction do
       item.save!
       data.save!
    end

     

  • Migration的迁移和回滚操作
    # 执行所有未执行的migration
    [ruby@dev project1]$ rails db:migrate
    
    # 查看数据库中migration的当前状态
    [ruby@dev project1]$ rails db:migrate:status
    warning ../package.json: No license field
    
    database: db/development.sqlite3
    
     Status   Migration ID    Migration Name
    --------------------------------------------------
       up     20201124051602  Create active storage tablesactive storage
       up     20201124065250  Create scores
       up     20201124073822  Create score items
    
    # 回滚一个migration,注意表中数据需要自行保存
    [ruby@dev project1]$ rails db:rollback
    [ruby@pms rparanking]$ rails db:rollback
    warning ../package.json: No license field
    == 20201124073822 CreateScoreItems: reverting =================================
    -- remove_index(:score_items, {:name=>"index_score_items_uniqueness"})
       -> 0.0032s
    -- remove_index(:score_items, {:column=>:scorer})
       -> 0.0032s
    -- drop_table(:score_items)
       -> 0.0038s
    == 20201124073822 CreateScoreItems: reverted (0.0135s) ========================
    
    [ruby@pms rparanking]$ rails db:migrate:status
    warning ../package.json: No license field
    
    database: db/development.sqlite3
    
     Status   Migration ID    Migration Name
    --------------------------------------------------
       up     20201124051602  Create active storage tablesactive storage
       up     20201124065250  Create scores
      down    20201124073822  Create score items
    
    [ruby@dev project1]$ rails db:rollback
    warning ../package.json: No license field
    == 20201124065250 CreateScores: reverting =====================================
    -- remove_index(:scores, {:column=>:score_times})
       -> 0.0055s
    -- remove_index(:scores, {:column=>:score})
       -> 0.0031s
    -- remove_index(:scores, {:column=>:pinyin})
       -> 0.0030s
    -- remove_index(:scores, {:column=>:name})
       -> 0.0035s
    -- remove_index(:scores, {:column=>:ename})
       -> 0.0020s
    -- drop_table(:scores)
       -> 0.0014s
    == 20201124065250 CreateScores: reverted (0.0215s) ============================
    
    [ruby@dev project1]$ rails db:migrate:status
    warning ../package.json: No license field
    
    database: db/development.sqlite3
    
     Status   Migration ID    Migration Name
    --------------------------------------------------
       up     20201124051602  Create active storage tablesactive storage
      down    20201124065250  Create scores
      down    20201124073822  Create score items
    
    # 执行db:migrate 回复所有migration状态为up
    # 回滚指定的migration,通过VERSION指定,所谓版本就是db/migrate/下面migration文件名最开始的那一串数字
    [ruby@dev project1]$ rails db:migrate:down VERSION=20201124065250
    # 执行特定的migration,通过VERSION指定,所谓版本就是db/migrate/下面migration文件名最开始的那一串数字
    [ruby@dev project1]$ rails db:migrate:up VERSION=20201124065250
    View Code

     

  • 命令行生成migration时,复杂数据类型(decimal)的语法 :
    # decimal的单引号时必要的
    rails g model Abc 'price:decimal{5,2}' supplier:references{polymorphic}

     

  • Model中自定义属性(数据库表中不存在),需要序列化为json的需要覆盖as_json
     # 扩展json对象,添加pinyin和jianpin属性
      def as_json data    
        if self.respond_to? 'name'
          ps = { pinyin: self.pinyin_name, jianpin: self.jianpin }
          super.merge ps
        end
      end

     

  • ActiveRecord对象 的修改痕迹追踪,记录在此

  • Model中的关系 has_one, has_many, 一定要想好是不是要加 dependent: :destroy,这个基于关联对象 是不是完全从属于 本对象
    has_many :jobs #, dependent: :destroy
  • Model中的关系 belongs_to, 如果主表数据可能被删除,要加 required false,否则本数据无法操作
      belongs_to :author, required: false

     

  • Migration中建立联合索引时,一定要指定名称,否则rollback时,会因为找不到生成的索引名称而报错
    add_index :score_items, [:score_id, :scorer], name: "index_score_items_uniqueness", unique: true

     

四、系统相关

  • 建立临时文件时,如何指定扩展名。rails建立临时文件很方便,直接Tempfile::newnew(basename="", tmpdir=nil, mode: 0, **options),但是如何给定一个扩展名呢?原来只需要在第一项参数位置给出一个数组即可,看代码

    irb(main):001:0> tf = Tempfile::new
    => #<Tempfile:/tmp/20201120-38479-dg7h2v>
    irb(main):002:0> tf.path
    => "/tmp/20201120-38479-dg7h2v"
    irb(main):003:0> tf = Tempfile::new('abc')
    => #<Tempfile:/tmp/abc20201120-38479-abc6ui>
    irb(main):004:0> tf.path
    => "/tmp/abc20201120-38479-abc6ui"
    irb(main):006:0> tf = Tempfile::new(['abc','txt'])
    => #<Tempfile:/tmp/abc20201120-38479-2prba5txt>
    irb(main):007:0> tf.path
    => "/tmp/abc20201120-38479-2prba5txt"
    irb(main):008:0> tf = Tempfile::new(['abc','.txt'])
    => #<Tempfile:/tmp/abc20201120-38479-n6a5j6.txt>
    irb(main):009:0>

      irb(main):020:0> tf = Tempfile.new ['','.jpg']
      => #<Tempfile:/tmp/20201120-38479-qkitzp.jpg>

     

 

五、程序发布

  •  config/enviroment/production.rb, 静态文件服务打开
    config.public_file_server.enabled = true

     

posted @ 2020-11-24 16:15  佣工7001  阅读(105)  评论(0编辑  收藏  举报