From 8742a5e5536f9a457ec82b094387ec6367210a6d Mon Sep 17 00:00:00 2001 From: Kevin Deisz Date: Fri, 24 Feb 2017 16:44:27 -0500 Subject: [PATCH] Style and docs Implement rubocop (with a couple rules turned off for easier migration) and document more methods. --- .rubocop.yml | 32 +++++++++++ Rakefile | 4 ++ .../connection_adapters/odbc_adapter.rb | 48 ++++++++-------- .../adapters/mysql_odbc_adapter.rb | 8 +-- .../adapters/postgresql_odbc_adapter.rb | 12 ++-- lib/odbc_adapter/column.rb | 3 + lib/odbc_adapter/column_metadata.rb | 4 +- lib/odbc_adapter/database_metadata.rb | 2 +- lib/odbc_adapter/database_statements.rb | 13 +++-- lib/odbc_adapter/quoting.rb | 6 +- lib/odbc_adapter/schema_statements.rb | 12 ++-- lib/odbc_adapter/type_caster.rb | 2 +- lib/odbc_adapter/version.rb | 2 +- odbc_adapter.gemspec | 1 + test/attributes_test.rb | 2 +- test/crud_test.rb | 2 +- test/registry_test.rb | 19 ++++--- test/test_helper.rb | 56 +++++++++++-------- 18 files changed, 145 insertions(+), 83 deletions(-) create mode 100644 .rubocop.yml diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..0a79d064 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,32 @@ +AllCops: + DisplayCopNames: true + DisplayStyleGuide: true + TargetRubyVersion: 2.0 + Exclude: + - 'vendor/**/*' + +Metrics/AbcSize: + Enabled: false + +Metrics/ClassLength: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Metrics/MethodLength: + Enabled: false + +Metrics/LineLength: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/PercentLiteralDelimiters: + PreferredDelimiters: + '%w': '[]' + '%i': '[]' diff --git a/Rakefile b/Rakefile index 4b2b7829..6af9c2b8 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,6 @@ require 'bundler/gem_tasks' require 'rake/testtask' +require 'rubocop/rake_task' Rake::TestTask.new(:test) do |t| t.libs << 'test' @@ -7,4 +8,7 @@ Rake::TestTask.new(:test) do |t| t.test_files = FileList['test/**/*_test.rb'] end +RuboCop::RakeTask.new(:rubocop) +Rake::Task[:test].prerequisites << :rubocop + task default: :test diff --git a/lib/active_record/connection_adapters/odbc_adapter.rb b/lib/active_record/connection_adapters/odbc_adapter.rb index 175be59b..8e29816b 100644 --- a/lib/active_record/connection_adapters/odbc_adapter.rb +++ b/lib/active_record/connection_adapters/odbc_adapter.rb @@ -18,6 +18,7 @@ module ActiveRecord class Base class << self + # Build a new ODBC connection with the given configuration. def odbc_connection(config) config = config.symbolize_keys @@ -27,7 +28,7 @@ def odbc_connection(config) elsif config.key?(:conn_str) odbc_conn_str_connection(config) else - raise ArgumentError, "No data source name (:dsn) or connection string (:conn_str) specified." + raise ArgumentError, 'No data source name (:dsn) or connection string (:conn_str) specified.' end database_metadata = ::ODBCAdapter::DatabaseMetadata.new(connection) @@ -36,6 +37,7 @@ def odbc_connection(config) private + # Connect using a predefined DSN. def odbc_dsn_connection(config) username = config[:username] ? config[:username].to_s : nil password = config[:password] ? config[:password].to_s : nil @@ -48,16 +50,9 @@ def odbc_dsn_connection(config) # e.g. "DSN=virt5;UID=rails;PWD=rails" # "DRIVER={OpenLink Virtuoso};HOST=carlmbp;UID=rails;PWD=rails" def odbc_conn_str_connection(config) - connstr_keyval_pairs = config[:conn_str].split(';') - driver = ODBC::Driver.new driver.name = 'odbc' - driver.attrs = {} - - connstr_keyval_pairs.each do |pair| - keyval = pair.split('=') - driver.attrs[keyval[0]] = keyval[1] if keyval.length == 2 - end + driver.attrs = config[:conn_str].split(';').map { |option| option.split('=', 2) }.to_h connection = ODBC::Database.new.drvconnect(driver) [connection, config.merge(driver: driver)] @@ -75,10 +70,12 @@ class ODBCAdapter < AbstractAdapter ADAPTER_NAME = 'ODBC'.freeze BOOLEAN_TYPE = 'BOOLEAN'.freeze - ERR_DUPLICATE_KEY_VALUE = 23505 - ERR_QUERY_TIMED_OUT = 57014 + ERR_DUPLICATE_KEY_VALUE = 23_505 + ERR_QUERY_TIMED_OUT = 57_014 ERR_QUERY_TIMED_OUT_MESSAGE = /Query has timed out/ + # The object that stores the information that is fetched from the DBMS + # when a connection is first established. attr_reader :database_metadata def initialize(connection, logger, config, database_metadata) @@ -86,23 +83,22 @@ def initialize(connection, logger, config, database_metadata) @database_metadata = database_metadata end - # Returns the human-readable name of the adapter. Use mixed case - one - # can always use downcase if needed. + # Returns the human-readable name of the adapter. def adapter_name ADAPTER_NAME end - # Does this adapter support migrations? Backend specific, as the - # abstract adapter always returns +false+. + # Does this adapter support migrations? Backend specific, as the abstract + # adapter always returns +false+. def supports_migrations? true end # CONNECTION MANAGEMENT ==================================== - # Checks whether the connection to the database is still active. This includes - # checking whether the database is actually capable of responding, i.e. whether - # the connection isn't stale. + # Checks whether the connection to the database is still active. This + # includes checking whether the database is actually capable of + # responding, i.e. whether the connection isn't stale. def active? @connection.connected? end @@ -119,7 +115,7 @@ def reconnect! end super end - alias :reset! :reconnect! + alias reset! reconnect! # Disconnects from the database if already connected. Otherwise, this # method does nothing. @@ -127,12 +123,16 @@ def disconnect! @connection.disconnect if @connection.connected? end + # Build a new column object from the given options. Effectively the same + # as super except that it also passes in the native type. + # rubocop:disable Metrics/ParameterLists def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil, native_type = nil) ::ODBCAdapter::Column.new(name, default, sql_type_metadata, null, table_name, default_function, collation, native_type) end protected + # Build the type map for ActiveRecord def initialize_type_map(map) map.register_type 'boolean', Type::Boolean.new map.register_type ODBC::SQL_CHAR, Type::String.new @@ -165,13 +165,14 @@ def initialize_type_map(map) alias_type map, ODBC::SQL_TYPE_TIMESTAMP, ODBC::SQL_TIMESTAMP end + # Translate an exception from the native DBMS to something usable by + # ActiveRecord. def translate_exception(exception, message) error_number = exception.message[/^\d+/].to_i - case - when error_number == ERR_DUPLICATE_KEY_VALUE + if error_number == ERR_DUPLICATE_KEY_VALUE ActiveRecord::RecordNotUnique.new(message, exception) - when error_number == ERR_QUERY_TIMED_OUT, exception.message =~ ERR_QUERY_TIMED_OUT_MESSAGE + elsif error_number == ERR_QUERY_TIMED_OUT || exception.message =~ ERR_QUERY_TIMED_OUT_MESSAGE ::ODBCAdapter::QueryTimeoutError.new(message, exception) else super @@ -180,6 +181,9 @@ def translate_exception(exception, message) private + # Can't use the built-in ActiveRecord map#alias_type because it doesn't + # work with non-string keys, and in our case the keys are (almost) all + # numeric def alias_type(map, new_type, old_type) map.register_type(new_type) do |_, *args| map.lookup(old_type, *args) diff --git a/lib/odbc_adapter/adapters/mysql_odbc_adapter.rb b/lib/odbc_adapter/adapters/mysql_odbc_adapter.rb index c9ccf13b..eaa690ef 100644 --- a/lib/odbc_adapter/adapters/mysql_odbc_adapter.rb +++ b/lib/odbc_adapter/adapters/mysql_odbc_adapter.rb @@ -16,7 +16,7 @@ def arel_visitor # Explicitly turning off prepared statements in the MySQL adapter because # of a weird bug with SQLDescribeParam returning a string type for LIMIT # parameters. This is blocking them from running with an error: - # + # # You have an error in your SQL syntax; ... # ... right syntax to use near ''1'' at line 1: ... def prepared_statements @@ -49,11 +49,11 @@ def unquoted_false 0 end - def disable_referential_integrity(&block) - old = select_value("SELECT @@FOREIGN_KEY_CHECKS") + def disable_referential_integrity(&_block) + old = select_value('SELECT @@FOREIGN_KEY_CHECKS') begin - update("SET FOREIGN_KEY_CHECKS = 0") + update('SET FOREIGN_KEY_CHECKS = 0') yield ensure update("SET FOREIGN_KEY_CHECKS = #{old}") diff --git a/lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb b/lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb index 285f7f4e..28a28f7c 100644 --- a/lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb +++ b/lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb @@ -6,7 +6,7 @@ class PostgreSQLODBCAdapter < ActiveRecord::ConnectionAdapters::ODBCAdapter BOOLEAN_TYPE = 'bool'.freeze PRIMARY_KEY = 'SERIAL PRIMARY KEY'.freeze - alias :create :insert + alias create insert # Override to handle booleans appropriately def native_database_types @@ -35,7 +35,7 @@ def default_sequence_name(table_name, pk = nil) "#{table_name}_#{pk || 'id'}_seq" end - def sql_for_insert(sql, pk, id_value, sequence_name, binds) + def sql_for_insert(sql, pk, _id_value, _sequence_name, binds) unless pk table_ref = extract_table_ref_from_insert_sql(sql) pk = primary_key(table_ref) if table_ref @@ -94,7 +94,7 @@ def create_database(name, options = {}) when :connection_limit " CONNECTION LIMIT = #{value}" else - "" + '' end end @@ -131,7 +131,7 @@ def remove_index!(_table_name, index_name) execute("DROP INDEX #{quote_table_name(index_name)}") end - def rename_index(table_name, old_name, new_name) + def rename_index(_table_name, old_name, new_name) execute("ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}") end @@ -149,8 +149,8 @@ def distinct(columns, orders) # Construct a clean list of column names from the ORDER BY clause, # removing any ASC/DESC modifiers order_columns = orders.map { |s| s.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '') } - order_columns.reject! { |c| c.blank? } - order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" } + order_columns.reject!(&:blank?) + order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s, i| "#{s} AS alias_#{i}" } "DISTINCT #{columns}, #{order_columns * ', '}" end diff --git a/lib/odbc_adapter/column.rb b/lib/odbc_adapter/column.rb index 31c099ff..36492a82 100644 --- a/lib/odbc_adapter/column.rb +++ b/lib/odbc_adapter/column.rb @@ -2,6 +2,9 @@ module ODBCAdapter class Column < ActiveRecord::ConnectionAdapters::Column attr_reader :native_type + # Add the native_type accessor to allow the native DBMS to report back what + # it uses to represent the column internally. + # rubocop:disable Metrics/ParameterLists def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, native_type = nil, default_function = nil, collation = nil) super(name, default, sql_type_metadata, null, table_name, default_function, collation) @native_type = native_type diff --git a/lib/odbc_adapter/column_metadata.rb b/lib/odbc_adapter/column_metadata.rb index ca34bedd..8f53bad8 100644 --- a/lib/odbc_adapter/column_metadata.rb +++ b/lib/odbc_adapter/column_metadata.rb @@ -13,7 +13,7 @@ class ColumnMetadata date: [ODBC::SQL_TYPE_DATE, ODBC::SQL_DATE, ODBC::SQL_TYPE_TIMESTAMP, ODBC::SQL_TIMESTAMP], binary: [ODBC::SQL_LONGVARBINARY, ODBC::SQL_VARBINARY], boolean: [ODBC::SQL_BIT, ODBC::SQL_TINYINT, ODBC::SQL_SMALLINT, ODBC::SQL_INTEGER] - } + }.freeze attr_reader :adapter @@ -56,7 +56,7 @@ def native_type_mapping(abstract, rows) create_params = selected_row[5] # Depending on the column type, the CREATE_PARAMS keywords can # include length, precision or scale. - if create_params && create_params.strip.length > 0 && abstract != :decimal + if create_params && !create_params.strip.empty? && abstract != :decimal result[:limit] = selected_row[2] # SQLGetTypeInfo: COL_SIZE end diff --git a/lib/odbc_adapter/database_metadata.rb b/lib/odbc_adapter/database_metadata.rb index bb0269f5..f3572e9c 100644 --- a/lib/odbc_adapter/database_metadata.rb +++ b/lib/odbc_adapter/database_metadata.rb @@ -11,7 +11,7 @@ class DatabaseMetadata SQL_MAX_TABLE_NAME_LEN SQL_USER_NAME SQL_DATABASE_NAME - ] + ].freeze attr_reader :values diff --git a/lib/odbc_adapter/database_statements.rb b/lib/odbc_adapter/database_statements.rb index 7971a42a..4c314c18 100644 --- a/lib/odbc_adapter/database_statements.rb +++ b/lib/odbc_adapter/database_statements.rb @@ -20,7 +20,7 @@ def execute(sql, name = nil, binds = []) # Executes +sql+ statement in the context of this connection using # +binds+ as the bind substitutes. +name+ is logged along with # the executed +sql+ statement. - def exec_query(sql, name = 'SQL', binds = [], prepare: false) + def exec_query(sql, name = 'SQL', binds = [], prepare: false) # rubocop:disable Lint/UnusedMethodArgument log(sql, name) do stmt = if prepared_statements @@ -42,7 +42,7 @@ def exec_query(sql, name = 'SQL', binds = [], prepare: false) values = dbms_type_cast(columns.values, values) column_names = columns.keys.map { |key| format_case(key) } - result = ActiveRecord::Result.new(column_names, values) + ActiveRecord::Result.new(column_names, values) end end @@ -52,7 +52,7 @@ def exec_query(sql, name = 'SQL', binds = [], prepare: false) def exec_delete(sql, name, binds) execute(sql, name, binds) end - alias :exec_update :exec_delete + alias exec_update exec_delete # Begins the transaction (and turns off auto-committing). def begin_db_transaction @@ -81,7 +81,10 @@ def default_sequence_name(table, _column) private - def dbms_type_cast(columns, values) + # A custom hook to allow end users to overwrite the type casting before it + # is returned to ActiveRecord. Useful before a full adapter has made its way + # back into this repository. + def dbms_type_cast(_columns, values) values end @@ -122,7 +125,7 @@ def native_case(identifier) # Assume column is nullable if nullable == SQL_NULLABLE_UNKNOWN def nullability(col_name, is_nullable, nullable) - not_nullable = (!is_nullable || nullable.to_s.match('NO') != nil) + not_nullable = (!is_nullable || !nullable.to_s.match('NO').nil?) result = !(not_nullable || nullable == SQL_NO_NULLS) # HACK! diff --git a/lib/odbc_adapter/quoting.rb b/lib/odbc_adapter/quoting.rb index af7bb732..a499612e 100644 --- a/lib/odbc_adapter/quoting.rb +++ b/lib/odbc_adapter/quoting.rb @@ -18,7 +18,7 @@ def quote_column_name(name) # If upcase identifiers, only quote mixed case names. if database_metadata.upcase_identifiers? - return name unless (name =~ /([A-Z]+[a-z])|([a-z]+[A-Z])/) + return name unless name =~ /([A-Z]+[a-z])|([a-z]+[A-Z])/ end "#{quote_char.chr}#{name}#{quote_char.chr}" @@ -33,9 +33,9 @@ def quoted_date(value) if value.respond_to?(zone_conversion_method) value = value.send(zone_conversion_method) end - value.strftime("%Y-%m-%d %H:%M:%S") # Time, DateTime + value.strftime('%Y-%m-%d %H:%M:%S') # Time, DateTime else - value.strftime("%Y-%m-%d") # Date + value.strftime('%Y-%m-%d') # Date end end end diff --git a/lib/odbc_adapter/schema_statements.rb b/lib/odbc_adapter/schema_statements.rb index 828a76ab..df149765 100644 --- a/lib/odbc_adapter/schema_statements.rb +++ b/lib/odbc_adapter/schema_statements.rb @@ -27,7 +27,7 @@ def views end # Returns an array of indexes for the given table. - def indexes(table_name, name = nil) + def indexes(table_name, _name = nil) stmt = @connection.indexes(native_case(table_name.to_s)) result = stmt.fetch_all || [] stmt.drop unless stmt.nil? @@ -38,7 +38,7 @@ def indexes(table_name, name = nil) result.each_with_object([]).with_index do |(row, indices), row_idx| # Skip table statistics - next if row[6] == 0 # SQLStatistics: TYPE + next if row[6].zero? # SQLStatistics: TYPE if row[7] == 1 # SQLStatistics: ORDINAL_POSITION # Start of column descriptor block for next index @@ -50,7 +50,7 @@ def indexes(table_name, name = nil) index_cols << format_case(row[8]) # SQLStatistics: COLUMN_NAME next_row = result[row_idx + 1] - if (row_idx == result.length - 1) || (next_row[6] == 0 || next_row[7] == 1) + if (row_idx == result.length - 1) || (next_row[6].zero? || next_row[7] == 1) indices << ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, format_case(index_name), unique, index_cols) end end @@ -58,7 +58,7 @@ def indexes(table_name, name = nil) # Returns an array of Column objects for the table specified by # +table_name+. - def columns(table_name, name = nil) + def columns(table_name, _name = nil) stmt = @connection.columns(native_case(table_name.to_s)) result = stmt.fetch_all || [] stmt.drop @@ -104,7 +104,9 @@ def foreign_keys(table_name) fk_from_table = key[2] # PKTABLE_NAME fk_to_table = key[6] # FKTABLE_NAME - ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(fk_from_table, fk_to_table, + ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new( + fk_from_table, + fk_to_table, name: key[11], # FK_NAME column: key[3], # PKCOLUMN_NAME primary_key: key[7], # FKCOLUMN_NAME diff --git a/lib/odbc_adapter/type_caster.rb b/lib/odbc_adapter/type_caster.rb index 4ca73c99..4839b51a 100644 --- a/lib/odbc_adapter/type_caster.rb +++ b/lib/odbc_adapter/type_caster.rb @@ -7,7 +7,7 @@ class TypeCaster ODBC::SQL_DATE, ODBC::SQL_TIME, ODBC::SQL_TIMESTAMP - ] + ].freeze attr_reader :idx diff --git a/lib/odbc_adapter/version.rb b/lib/odbc_adapter/version.rb index bd110b5f..693cb713 100644 --- a/lib/odbc_adapter/version.rb +++ b/lib/odbc_adapter/version.rb @@ -1,3 +1,3 @@ module ODBCAdapter - VERSION = '5.0.2' + VERSION = '5.0.3'.freeze end diff --git a/odbc_adapter.gemspec b/odbc_adapter.gemspec index 153eda0b..d93a71a9 100644 --- a/odbc_adapter.gemspec +++ b/odbc_adapter.gemspec @@ -26,4 +26,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'rake', '~> 10.0' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'simplecov', '~> 0.12' + spec.add_development_dependency 'rubocop', '~> 0.47' end diff --git a/test/attributes_test.rb b/test/attributes_test.rb index ea24e19c..8a0cbf43 100644 --- a/test/attributes_test.rb +++ b/test/attributes_test.rb @@ -7,7 +7,7 @@ def test_booleans? end def test_integers - assert_kind_of Fixnum, User.first.letters + assert_kind_of Integer, User.first.letters end def test_strings diff --git a/test/crud_test.rb b/test/crud_test.rb index de2ba082..39665a35 100644 --- a/test/crud_test.rb +++ b/test/crud_test.rb @@ -3,7 +3,7 @@ class CRUDTest < Minitest::Test def test_creation with_transaction do - user = User.create(first_name: 'foo', last_name: 'bar') + User.create(first_name: 'foo', last_name: 'bar') assert_equal 7, User.count end end diff --git a/test/registry_test.rb b/test/registry_test.rb index b829fd03..eb1afe2c 100644 --- a/test/registry_test.rb +++ b/test/registry_test.rb @@ -3,20 +3,25 @@ class RegistryTest < Minitest::Test def test_register registry = ODBCAdapter::Registry.new + register_foobar(registry) + adapter = registry.adapter_for('Foo Bar') + assert_kind_of Class, adapter + assert_equal ODBCAdapter::Adapters::MySQLODBCAdapter, adapter.superclass + assert_equal 'foobar', adapter.new.quoted_true + end + + private + + # rubocop:disable Lint/NestedMethodDefinition + def register_foobar(registry) require File.join('odbc_adapter', 'adapters', 'mysql_odbc_adapter') registry.register(/foobar/, ODBCAdapter::Adapters::MySQLODBCAdapter) do - def initialize - end + def initialize() end def quoted_true 'foobar' end end - - adapter = registry.adapter_for('Foo Bar') - assert_kind_of Class, adapter - assert_equal ODBCAdapter::Adapters::MySQLODBCAdapter, adapter.superclass - assert_equal 'foobar', adapter.new.quoted_true end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 7aa93c99..65cc6d52 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -35,35 +35,43 @@ class User < ActiveRecord::Base scope :lots_of_letters, -> { where(arel_table[:letters].gt(10)) } - create([ - { first_name: 'Kevin', last_name: 'Deisz', letters: 10 }, - { first_name: 'Michal', last_name: 'Klos', letters: 10 }, - { first_name: 'Jason', last_name: 'Dsouza', letters: 11 }, - { first_name: 'Ash', last_name: 'Hepburn', letters: 10 }, - { first_name: 'Sharif', last_name: 'Younes', letters: 12 }, - { first_name: 'Ryan', last_name: 'Brown', letters: 9 } - ]) + create( + [ + { first_name: 'Kevin', last_name: 'Deisz', letters: 10 }, + { first_name: 'Michal', last_name: 'Klos', letters: 10 }, + { first_name: 'Jason', last_name: 'Dsouza', letters: 11 }, + { first_name: 'Ash', last_name: 'Hepburn', letters: 10 }, + { first_name: 'Sharif', last_name: 'Younes', letters: 12 }, + { first_name: 'Ryan', last_name: 'Brown', letters: 9 } + ] + ) end class Todo < ActiveRecord::Base belongs_to :user end -User.find(1).todos.create([ - { body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', published: true }, - { body: 'Praesent ut dolor nec eros euismod hendrerit.' }, - { body: 'Curabitur lacinia metus eget interdum volutpat.' } -]) +User.find(1).todos.create( + [ + { body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', published: true }, + { body: 'Praesent ut dolor nec eros euismod hendrerit.' }, + { body: 'Curabitur lacinia metus eget interdum volutpat.' } + ] +) -User.find(2).todos.create([ - { body: 'Nulla sollicitudin venenatis turpis vitae finibus.', published: true }, - { body: 'Proin consectetur id lacus vel feugiat.', published: true }, - { body: 'Pellentesque augue orci, aliquet nec ipsum ultrices, cursus blandit metus.' }, - { body: 'Nulla posuere nisl risus, eget scelerisque leo congue non.' }, - { body: 'Curabitur eget massa mollis, iaculis risus in, tristique metus.' } -]) +User.find(2).todos.create( + [ + { body: 'Nulla sollicitudin venenatis turpis vitae finibus.', published: true }, + { body: 'Proin consectetur id lacus vel feugiat.', published: true }, + { body: 'Pellentesque augue orci, aliquet nec ipsum ultrices, cursus blandit metus.' }, + { body: 'Nulla posuere nisl risus, eget scelerisque leo congue non.' }, + { body: 'Curabitur eget massa mollis, iaculis risus in, tristique metus.' } + ] +) -User.find(4).todos.create([ - { body: 'In hac habitasse platea dictumst.', published: true }, - { body: 'Integer molestie ornare velit, eu interdum felis euismod vitae.' } -]) +User.find(4).todos.create( + [ + { body: 'In hac habitasse platea dictumst.', published: true }, + { body: 'Integer molestie ornare velit, eu interdum felis euismod vitae.' } + ] +)