这真的很难在谷歌上搜索,因为我不知道这是Ruby的东西还是Rails的东西,而且谷歌在搜索"on"方面做得不好

在一个如下所示的文件中

# app/models/concerns/searchable.rb
module Searchable
  extend ActiveSupport::Concern

  included do
    include Elasticsearch::Model
    include Elasticsearch::Model::Callbacks

    # Every time our entry is created, updated, or deleted, we update the index accordingly.
    after_commit on: %i[create update] do
      __elasticsearch__.index_document
    end

    after_commit on: %i[destroy] do
      __elasticsearch__.delete_document
    end

    # We serialize our model's attributes to JSON, including only the title and category fields.
    def as_indexed_json(_options = {})
      as_json(only: %i[title category])
    end

    # Here we define the index configuration
    settings settings_attributes do
      # We apply mappings to the title and category fields.
      mappings dynamic: false do
        # for the title we use our own autocomplete analyzer that we defined below in the settings_attributes method.
        indexes :title, type: :text, analyzer: :autocomplete
        # the category must be of the keyword type since we're only going to use it to filter articles.
        indexes :category, type: :keyword
      end
    end

    def self.search(query, filters)
      # lambda function adds conditions to the search definition.
      set_filters = lambda do |context_type, filter|
        @search_definition[:query][:bool][context_type] |= [filter]
      end

      @search_definition = {
        # we indicate that there should be no more than 5 documents to return.
        size: 5,
        # we define an empty query with the ability to dynamically change the definition
        # Query DSL https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html
        query: {
          bool: {
            must: [],
            should: [],
            filter: []
          }
        }
      }

      # match all documents if the query is blank.
      if query.blank?
        set_filters.call(:must, match_all: {})
      else
        set_filters.call(
          :must,
          match: {
            title: {
              query: query,
              # fuzziness means you can make one typo and still match your document.
              fuzziness: 1
            }
          }
        )
      end

      # the system will return only those documents that pass this filter
      set_filters.call(:filter, term: { category: filters[:category] }) if filters[:category].present?

      # and finally we pass the search query to Elasticsearch.
      __elasticsearch__.search(@search_definition)
    end
  end

  class_methods do
    def settings_attributes
      {
        index: {
          analysis: {
            analyzer: {
              # we define a custom analyzer with the name autocomplete.
              autocomplete: {
                # type should be custom for custom analyzers.
                type: :custom,
                # we use a standard tokenizer.
                tokenizer: :standard,
                # we apply two token filters.
                # autocomplete filter is a custom filter that we defined above.
                # and lowercase is a built-in filter.
                filter: %i[lowercase autocomplete]
              }
            },
            filter: {
              # we define a custom token filter with the name autocomplete.

              # Autocomplete filter is of edge_ngram type. The edge_ngram tokenizer divides the text into smaller parts (grams).
              # For example, the word “ruby” will be split into [“ru”, “rub”, “ruby”].

              # edge_ngram is useful when we need to implement autocomplete functionality. However, the so-called "completion suggester" - is another way to integrate the necessary options.
              autocomplete: {
                type: :edge_ngram,
                min_gram: 2,
                max_gram: 25
              }
            }
          }
        }
      }
    end
  end
end

我不确定after_commit on: %i[create update] do应该是什么意思. 我设法找到了这条信息 这给了我一个如何使用这个系统的 idea . 但我仍然不确定"on:"这个语法是如何创建的.这看起来不像是Ruby的事情.它看起来像是Rails对某些东西的速记,但它到底是什么?

另外,有没有列出Rails提供的所有缩写的来源?要弄清楚某个东西是Rails速记还是Ruby语法,是一件非常痛苦的事情.

推荐答案

让我们分析一下中的语法的各个部分

after_commit on: %i[create update] do
  # ...
end

首先,关于末尾的array.它使用Ruby的%语法来创建一个对象,在本例中是一个符号array.因此,%i[create update]相当于[:create, :update]

有多种选项可以使用这种%语法来创建各种对象,例如,%[foo]相当于"foo",%w[foo bar]相当于["foo", "bar"].此处的分隔符字符是任意的.除了[],你还可以使用{},甚至可以使用%i|foo bar|或%i.foo bar`.有关详情,请参阅syntax documentation.

第二,on:.在这里,您将关键字参数on传递给after_commit方法,并将符号数组传递给它.关键字参数类似于可以传递给方法的常规位置参数,您只需将参数值与名称一起传递,类似于Hash.

从历史上看,Ruby支持将Hash作为方法的最后一个参数传递,并允许省略那里的大括号(这样您就可以使用after_commit(on: [:create, :update])而不是after_commit({:on => [:create, :update]}).Ruby的关键字参数(最早是在Ruby 2.0中引入的)构建在这种语法之上,并在此过程中对语义进行了一些改进.不过,在大多数情况下,它的工作方式仍然与将带有符号键的Hash传递给方法时相同.请注意,这不同于例如Python.位置参数和关键字参数不能任意混合.

您可以在the respective documentation中了解有关关键字参数(和常规位置参数)的更多信息.

因此,该方法调用等同于:

after_commit(on: [:create, :update]) do
  # ...
end

on ... end部分是一个block,它被传递给after_commit方法,这是另一种Ruby语法.这允许将代码块传递给方法,该方法可以对此做一些事情,类似于您可以在Java脚本中传递匿名函数的方式.块在Ruby中被广泛使用,因此了解它们很重要.

最后,Rails定义了after_commit方法及其相关行为.它用于注册在特定事件上运行的回调(在本例中,用于在创建或更新当前ActiveRecord模型的数据库事务成功提交后运行一些代码).

在关于ActiveRecord callbacks的文档中对此进行了描述.

Ruby-on-rails相关问答推荐

rails中Net::STP的多文件模式

我使用rbenv安装Ruby,但我在使用";gem";->;错误:执行gem时遇到此错误.(Errno::EACCES)权限被拒绝

Rails 7.1,登录到STDOUT和LOG/Production.log

组织和/或存储我一直在 RSpec 中使用的模拟对象的最佳方式是什么?

正确更新其他列的更新列

Rails 3 应用程序的 MySQL 集群 (NDB) 与 MySQL 复制 (InnoDB):优点/缺点?

FactoryGirl 和 Rspec 测试中 attributes_for 的含义

简单表单关联自定义标签名称

机械师 vs FactoryGirl - 优点和缺点

Heroku 错误 R14(超出内存配额):我该如何解决?

如何在我的 Gemfile 中找到未使用的Ruby

Rails 4 查找没有子元素的父母

activerecord 查找所有未包含在数组中的内容

Rails 3.1 在开发模式下非常慢,因为assets资源 ,怎么办?

Redis 引发需要 NOAUTH 身份验证错误,但没有设置密码

批量查找 mongoDB 记录(使用 mongoid ruby​​ 适配器)

何时使用 Helpers 而不是 Partials

我是否必须手动卸载所有依赖的 gem?

错误:无法在 Mavericks 上构建 gem 原生扩展

如何使用 url 连接到 postgresql