go Rails 知识点,Concepts Series:url和parameter; 建立Rails App Templates;报错页面debug; counter_cache

时间:2021-01-09 09:26:55

Rails Concepts Series:

https://gorails.com/series/rails-concepts

  1. 基本都是免费的
  2. 一些细小的知识点,很有帮助。
  • URL和parameter 的简单解析
  • 做一个app template
  • 使用 Ruby on Rails 的❌页面debug
  • rails5的actioncable和websockets介绍(有多个系列的cable视频)
  • Form的submit方法解释:params[:commit] == value
  • 记录关联中的选项:counter_cache


URL和parameter 的简单解析。

http://localhost:3000/products?test=111 

在routes.rb中

get '/products', to: "products#indx"

Rails routes会解析url,提取一个参数: params[:test] = 111

这个参数传给controller中的 Product#index:

@test =  params[:test]

在views/products/index.html.erb写:

<%= @test%>

最后会在web page 上显示。

http://localhost:3000/products/dd?test=111

在routes.rb中

get '/products', to: "products#index"

get '/products/id', to: 'products#show'

Rails routes会解析url,提取2个参数: id和test

这个2参数传给controller中的 Product#show:

@test =  params[:test]

@id = params[:id]

在views/products/index.html.erb写:

<%= @test%> <%= @id%>

最后会在web page 上显示这2个参数

在termiinal的log上,会出现:Parameters: {"test" => "111",  "id" => "dd"}



做一个app template

Rails指导:

http://guides.rubyonrails.org/generators.html#application-templates

(一点感悟,光看指导,看不明白,理解不清楚。还是视频比较好,有step to step。方便理解)

视频教程:

https://gorails.com/episodes/rails-application-templates?autoplay=1

教程案例:本地:/自我练习/jumpstart-master/whatever

⚠️,不难理解,但是有很多兼容性等问题,需要测试模版是否好使。所以使用现成的模版稍微修改比较好。


基础:

使用-m参数建立一个预制自定义gem的Rails app。

rails new myapp -m template.rb

下载git上的zip压缩包, Download ZIP,  解压缩后在,那个文件夹运行上面的命令。

也可以使用线上模版如:

rails new myapp -m https://raw.github.com/80percent/rails-template/master/composer.rb

打开模版设置的文件的命令是:atom template.rb

文档的理解:

先设定方法:

  1. 定义add_template_repository_to_source_path
  2. 定义add_gems,即所要增加的gem
  3. 定义set_application_name
  4. 每个gem各自的设置,都需要定义。比如devise,需要def add_users, 挺复杂的,需要根据各自的gem使用文档来设置。
  5. 其他一些相关设置,比如打开spring。
  6. 执行上面的方法。在add_gems后,使用after_bundle(&block), 结束。
after_bundle do
  set_application_name
  stop_spring
  add_users
 ...略
  add_announcements
  add_notifications
  add_multiple_authentication
  add_friendly_id
  copy_templates
  # Migrate
  rails_command "db:create"
  rails_command "db:migrate"
  # Migrations must be done before this
  add_administrate
  add_whenever
  add_sitemap
  git :init
  git add: "."
  git commit: %Q{ -m 'Initial commit' }
end


如何使用 Ruby on Rails 的❌页面debug

弹出红色页面:

首先要看标题,和标题下的解释。页面最下方有控制台,可以进行变量的输入测试反馈。

如果不能找到问题。则需要看下面的一大堆stack tracks。

例子

actionpack(3.2.8) lib/action_controller/metal/data_streaming.rb:125:in 'send_file_headers!'

。。。略。。一堆

app/controllers/charges_chntroller.rb:13:in 'block (2 levels) in show'

...

第一行actionpack(3.2.8) ...,指actionpack的版本,及出错的文件位置。这是源代码库的代码。往下看,找到自己写的代码的文件app/controllers/..., 然后回到atom查看细节。

如果你怀疑这是一个方法使用的错误,看看是否用错参数及其格式。可以去API上查询此方法的详细信息。

还是找不到问题的话,并猜测是否是actionpack版本过期了?

可以去git上rails/rails, 找对应的版本分支,根据文件路径打开对应的文件,并定位。

右上角有一个blame按钮,可以查看这行代码之前的变更记录。

总之,报错页的的标题,是可以定位bug,比如通过复制粘到google上查询类似问题,比较注重速度和效率。但查stack track才能够最准确的定位问题。这叫做读你的代码的故事。

如果询问别人问题,把stack track粘贴上,很重要。

第一步,看错误标题及相关。这通常可以有效率解决问题,如果不能看第二步⬇️。

第二步,通过stack track看最后列出的你写的code。 并确认是否是正确的。如果还不能解决问题。见第三步⬇️。

第三步, 查看源代码库,通过第一行的版本和路径查看。



什么是webstocket和actioncable

之前学习的博客:http://www.cnblogs.com/chentianwei/p/8690304.html

这章节过于基础,我需要一个完整的,最好是实际的产品的教学。看下面系列2.

有2个系列:



Rails Forms with Multiple Submit Buttons

讲解ActionView::Helpers::Formbuilder#submit(value =nil, options={})

还有一个submit_tag(value = "提交", options={})

submit方法会根据对象是否是new而在controller中选择是create还是update。

另外,开发者可以根据value的值,定义不同的额外行为。例子见下:

⚠️解析成HTML,input标签内有name, value,2个特性:

submit_tag "Complete sale", data: { disable_with: "Submitting..." }
# => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" />

这2个特性组成了,在点击提交按钮后,request中的参数之一: {..., "commit" => "提交"}

因此,params[:commit] 的值是"提交"。 根据value的不同,可以在同一个表格使用多个按钮, 并在controller中,设定针对不同value的不同方法。

比如,在创建或者更新的web页面,在“发布”按钮旁边增加一个“不发布“按钮。这两个按钮都会创建或更新一个记录,但会根据value,进行后续的行为,这里可以在index的页面隐藏“不发布”的记录。

button,button_tag方法和submit方法的相似和区别:

  • 都可以作为提交按钮,默认设置 type="submit"
  • button可以接受一个块参数。type特性可以设置其他类型,如"reset" 或者javascript。


Active Record Associations中的:counter_cache

前置知识:

Controlling caching:

第一次从关联对象来查询数据,是从数据库中查询,查询结果会存储在缓存中。方便之后直接从缓存查询,速度提高。

但有时候数据库更新太快。因此更新缓存, 使用reload方法。

  1. author.books  #从数据库取查询记录books
  2. author.books.size #从cache中得到
  3. author.books.reload.empty? #丢弃cache,从数据库取数据。

Controlling Association Scope

默认的关联对象之间是处于同一个模型module的scope范围。但例外是:如果两个对象定义在不同的scopes中,关联会失效,这是必须指定class_name ,明确说明属于哪个模型的类。

案例见:http://guides.rubyonrails.org/association_basics.html#tips-tricks-and-warnings

另外,也可以用于自定义一个关联的对象名字,然后用class_name说明关联的真正类。 

module MyApplication
  module Business
    class Supplier < ApplicationRecord
      has_one :account,
        class_name: "MyApplication::Billing::Account"
    end
  end
 
  module Billing
    class Account < ApplicationRecord
      belongs_to :supplier,
        class_name: "MyApplication::Business::Supplier"
    end
  end
end

Bi-directional Associations  双向关联

默认简单的两个模型的关联,当一条记录的属性被改变,但没储存到数据库,关联记录是可以从缓存中得到这个改变的属性的。

a = Author.first

b = a.books.first

a.first_name == b.author.first_name  返回true

a.first_name = "David" #没有保存到数据库,只是保存到缓存了。

a.first_name == b.author.first_name   从缓存中进行比较,返回true

但是如果关联包含scope或者如:through, :foreign_key 等选项,

即间接的关联 ,则

a.first_name == b.author.first_name 返回false

可以使用inverse_of选项,来建立bi-directional 关联:

如:

class Author < ApplicationRecord

has_many :books, inverse_of: "writer"

end

class Book < ApplicationRecord

belongs_to :writer, class_name: "Author", foreign_key: "author_id"

end


counter_cache

查询@author.books.size的值,通过执行数据库语法COUNT(*) query.

但无需每次都调用数据库。比如用在微博主页,每个大vip有多少粉丝。 对非时效性和准确性的数据,可以降准提速。

在belongs_to上加上选项counter_cache:true,Rails会把缓存的value更新到数据库,然后返回这个值来响应size方法。

⚠️, 在Author上需要有一个column  books_count 

(类名_count)

我的理解:第一次调用@author.books.size,会使用数据库计算,并存入books_count,下次再用就从books_count中调用数据了。

另外可以使用counter_cache: :自定义名字,来替代true,然后在has_many的表中定义这个名字作为列名。

class Book < ApplicationRecord
  belongs_to :author, counter_cache: true
end
class Author < ApplicationRecord
  has_many :books
end

这样,如果增加了一条Book记录,会自动更新Author中对应的author.books_count。

同样,如何删除一条Book记录,也会自步更新author.books_count的数量,-1.


ActiveRecord::CounterCache::ClassMethods

有一个reset_counters方法, 一般用于重置。

比如以前没有使用counter_cache,现在已经有了一堆相关的记录。可以:

rails g migration addXXX,然后在db/migrate/XXX_add_xxx中添加:

add_column :users, :forum_posts_count, :integer, default: 0, null: false

User.find_each {|u| User.reset_counters(u.id, :forum_posts)}

数据量非常大的时候,加上 batch_size: 1000

find_each(batch_size: 1000) do ...end

或者使用原始SQL语法:

execute <<-SQL.squish

update users set forum_posts_count = (

select count(1) from forum_posts where forum_posts.user_id = users.id

)