Вы можете объяснить, что происходит в этом коде Ruby?


Я пытаюсь выучить Ruby, а также Ruby on Rails прямо сейчас. Я следую вместе с Learning Rails, 1-е издание, но мне трудно понять некоторые части кода.

Я обычно работаю на C, C++ или Java, так что Ruby-это довольно большое изменение для меня.

В настоящее время я озадачен следующим блоком кода для миграции базы данных:

  def self.up
    create_table :entries do |t|
      t.string :name
      t.timestamps
    end
  end

Откуда берется переменная t? Что же она на самом деле представляет? Это что-то вроде "Я" в a для оператора(i=0;i

Кроме того, где определяются записи:? (записи-это имя моего контроллера, но откуда эта функция знает об этом?)

10   6  

10 ответов:

:entries является буквальным символом, это буквальное значение, такое как 7 или "a string". Здесь нечего определять (кстати, функция не знает о названии вашего контроллера).

t является параметром блока, который вы передали в метод create_tables. То, что вы написали здесь, примерно аналогично чему-то вроде:

void anonymous_block(Table *t) {
   t->string("name");
   t->timestamps();
}

...

create_table("entries", &anonymous_block);

На Языке C++. create_table вызывает ваш блок и передает ему параметр, который вы назвали t. Я бы посоветовал вам взять вступительную книгу для ruby в отличие от рельсов. Я рекомендую Ruby For Rails Дэвида А. Блэка.

Я возьму эту штуку t. Метод create_table подобен функции C, которая берет указатель на функцию, которая принимает один аргумент, объект определения таблицы (простите мои несуществующие навыки C):

void entries_table_constructor(TableDef table_definition) {
  table_def_add_string_column(table_definition, "name");
  table_def_add_timestamps_column(table_definition);
}    

create_table("entries", entries_table_constructor);
Но в Ruby определение передаваемой функции может быть выполнено в момент вызова метода create_table. Таким образом, бит между do и end подобен функции entries_table_constructor, а переменная t подобна аргументу table_definition.

Существует большая разница между функцией однако указатели в C и блоки в Ruby. В Ruby все локальные переменные вне блока доступны внутри блока:

a = 10
create_table :entries do |t|
  puts a
  ...
end

Проверьте ключевое слово yield в Ruby, чтобы увидеть, как написать свои собственные методы, такие как create_table.

:entries-ссылка на таблицу entries в Rails.

Насколько я понимаю, мигратор должен был знать об этом, когда была дана команда "создать контроллер" (работал с Rails профессионально в течение года, но все еще учился).

Что касается |t|, то это блок. Чтобы процитировать книгу кирки (которую вы должны немедленно получить копию pdf или версию мертвого дерева):

Блоки могут быть использованы для определения фрагмента кода, который должен выполняться под каким-либо видом транзакционный контроль. Например, вы часто открываете файл, делаете что-то с его содержимым, а затем хотите убедиться, что файл закрыт, когда вы закончите. Хотя вы можете сделать это с помощью обычного кода, есть аргумент для того, чтобы сделать файл ответственным за само закрытие. Мы можем сделать это с помощью блоков.

Итак, то, что происходит выше, заключается в том, что |t| - это блок, который обрабатывает настройку соединения с базой данных, создавая строки в соответствии с их конкретными типами, а затем закрыть соединение.

Вот еще один пример:

output_string = "Let's print this to file"

File.open('outputfile.txt','w') do |f| #f for file
  f.print output_string
end

Что касается вашего итератора, да, вы можете сделать и это:

an_array = [1,2,3,4]
an_array.each do |line|#line is the block for the elements of the array during iteration
   puts "Now we are at: #{line.to_s}!" 
end

Create_table-это метод, который принимает лямбда-выражение (своего рода делегат), t-аргумент делегата. Поэтому, когда вы выполняете create_table, он выполняет

t.string :name
t.timestamps

Что-то вроде псевдокода

delegate d = funciton (t) {
   t.string :name
   t.timestamps
}
create_table(d);
Прямым аналогом в java являются анонимные классы..
addReturnBackListener(new Listener<EventObject>() {
  public void handle(EventObject e) {
     refreshAndShowAndList();
  }
});

": entries " вообще не определяется, это просто идентификатор. Вы можете рассматривать его как простую строку (но не тратя память на хранение символов).

Метод create_table - это то, что известно как блок в Ruby, аt - это переменная, локальная для этого блока (t - это просто соглашение в миграциях Rails, которое расшифровывается как "таблица"). Это еще один более очевидный пример блока Ruby:

10.times do |i|
  print "i is #{i}"
end

:entries это символ Рубина, который является своего рода легкой строкой, используемой для именования вещей. Вы могли бы также использовать "entries". Одним из распространенных способов использования символов является указание ключей в хэше. В любом случае, создаваемая таблица является названные "записи".

Я работаю над приложением, которое также имеет Entry Модель / entries таблицу. Вот моя миграция:

class CreateEntries < ActiveRecord::Migration
  def self.up
    create_table :entries do |t|
      t.string :title
      t.text :entry
      # ...
    end
  end

  def self.down
    drop_table :entries
  end
end
Очень похоже на то, на что вы смотрите.

Во-первых, первая строка, объявляющая класс под названием CreateEntries, который расширяет ActiveRecord::Migration.

Далее объявляется метод класса с именем up(). Метод класса, в отличие от метода экземпляра, принадлежит классу, а не конкретным объектам класса. Это ключевое слово " self", которое заставляет его быть классом метод.

Следующий вызов create_table() и передача ему двух вещей:

  1. Символ (":entries"), который, как упоминалось выше, похож на строковый литерал. Это говорит ActiveRecord, что таблица, которую он создает, должна называться. Допустим, вы набрали этот код вручную-забудьте на минуту о генераторах. Вы набрали ":entries", потому что знаете, что по соглашению таблицы в приложении Rails называются существительными множественного числа, и вы знаете, что класс модели, который подключается к этой таблице, будет называться Entry.

  2. Тоже проезжая квартал.

Блок может быть заключен...

`do ... end`

Или по

`{ ... }`

Блок может принимать параметры, заключенные в два "|"s. в этом случае метод create_table передает блоку объект класса TableDefinition, поэтому, чтобы ответить на один из ваших вопросов, t является var, содержащим этот объект. Затем внутри блока мы вызываем различные методы экземпляра TableDefinition.

Откуда взялся объект TableDefinition? Тот происходит в методе create_table(). Он содержит код, который создает экземпляр нового объекта TableDefinition и "выдает" его блоку....

Исходный код ActiveRecord...

def create_table(table_name, options = {})
  table_definition = TableDefinition.new(self)
  table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false

  yield table_definition

  # ...

end

Записи-это ссылка на вашу модель записи - каждая модель предполагает, что имя таблицы будет таким же, как и ее имя, за исключением таблицы.(http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/String/Inflections.html#M001653)

T-это параметр блока, передаваемый в метод create_table, см. http://www.rubycentral.com/book/tut_containers.html для лучшего примера. В этом случае t означает таблицу, которая была создана (http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#M002191)

Надеюсь, этого будет достаточно, чтобы помочь вам

Это типичное использование блоков в Ruby. Метод create_table определяется в ActiveRecord следующим образом:

def create_table(table_name)
  table_object = some_table_setup
  yield(table_object) # your code block which was passed implicitly is invoked here
  create_table(table_object)
end

:entries это определяется прямо там. Код вызывает метод create_table с двумя аргументами-желаемым именем таблицы и блоком кода.

Create_table построит объект TableDefinition и затем уступит блоку кода, поставляя ему этот объект. Внутри блока кода он будет называться t. И, наконец, этот блок кода вызывает некоторые методы на t для построения столбцов.

Поскольку, исходя из Python, я сам пытался понять эту конструкцию, я приведу неэфтонный перевод вашего фрагмента кода.

Во-первых, вы должны были бы определить функцию create_table как эту (Это просто скелет):

def create_table(name, setup):
    t = Table(name)
    setup(t)

Затем для каждой таблицы вы создадите функцию настройки в виде:

def setup_entries(t): # <-- here is your |t|, just a function argument
    t.string("name")
    t.timestamps()

И, наконец, вы создадите таблицу, вызвав:

create_table("entries", setup_entries)

Это не так, как это было бы сделано с Python. Если вы заинтересованы в том, как создавать таблица в Python вы должны посмотреть, как django , или sqlalchemy обрабатывать это.