紙一重の積み重ね

アラフォーのエンジニアがなれる最高の自分を目指して、学んだことをこつこつ情報発信するブログです。

【N+1問題対策】Ransackとincludesメソッドを使ってActiveRecordの多段の関連を検索する方法 #Rails5

f:id:yokoyantech:20181029174950p:plain

はじめに

N+1問題を解消するために、複数の関連を持つModelをincludesメソッドで解消する方法をメモ。

実行環境

  • Rails5.2.0
  • Ransack
  • Slim

Model定義

Userに持っている名称と、Corporationに持っている名称を取得したい。

class User < ApplicationRecord
  has_one :customer, dependent: :destroy

class Customer < ApplicationRecord
  belongs_to :user
  has_many :points, dependent: :destroy

class Point < ApplicationRecord
  belongs_to :customer
  belongs_to :corporation

class Corporation < ApplicationRecord
  has_many :points, dependent: :destroy

実装例

Controller

@q = Point.ransack(query)
result = @q.result
@points = result
            .includes([{ customer: :user }, :corporation])
            .joins([{ customer: :user}, :corporation])
            .select("users.user_name,
                     corporations.company_name,
                     points.*")

View(Slim)

検索条件

customer_userとなるのがポイント。

th = sort_link @q, :customer_user_user_name, t("activerecord.attributes.user.user_name")

検索結果表示

- @points.each do |point|
  tr
    td = point.customer.user.user_name
    td = point.corporation.company_name

【Python+Postgres】'int' object does not support indexingが発生したときの対処法。タプルの要素が1つの場合でもカンマが必要。

f:id:yokoyantech:20181012183231p:plain

はじめに

Psycopg2のmogrifyにint型の要素を1つ渡して、エスケープしたSQLを取得しようとしたらエラーになったのでメモ。

環境

  • AWS Lambda
  • Python3.6
  • PostgreSQL9.6

発生したエラー

"errorMessage": "'int' object does not support indexing",
"errorType": "TypeError

原因

タプルの要素が1つの場合の文法が誤っているため。具体的にはカンマがないため。

ダメな例

query = "DELETE FROM public.hoge WHERE hoge_id = %s"
values = (fuga.id)
sql = mogrify_query(cur, query, values)

処置

タプルの要素が1つでもカンマを付与する。公式ドキュメントにも記載がある通り、タプルを作るのはカンマ。丸括弧ではない。

なお、タプルを作るのはカンマであり、丸括弧ではありません。

4. 組み込み型 — Python 3.6.5 ドキュメント

修正例

query = "DELETE FROM public.hoge WHERE hoge_id = %s"
values = (fuga.id,)
sql = mogrify_query(cur, query, values)

【Rails5.2.0】ActiveRecord::DangerousAttributeError association is defined by Active Record. が発生したときの対処法 #Rails #ActiveRecord

f:id:yokoyantech:20181005130407p:plain

はじめに

Rails5.2.0でアプリケーションを開発中に見慣れないエラーが出たのでメモ。

実行環境

  • Rails5.2.0
  • ActiveRecord5.2.0
  • PostgreSQL 9.6

発生したエラー

ActiveRecord::DangerousAttributeError

association is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name.

参考情報

st40.xyz

これは、ActiveRecordで利用されているプロパティやメソッド名とDBのカラム名が同じ名前の場合に出力されるエラーのようです。 自分の環境では「model_name」や「changed」といったものがダメでした。他にも「hash」や「save」といったもの使えないようです。

kakakakakku.hatenablog.com

正確に言うと hash だけじゃなくて ActiveRecord::Base に実装されているメソッド名は基本的にダメっていう理解で正しいと思う.例えば save もそう.

原因

自分が設計したDBのカラム名と、ActiveRecordで利用されているプロパティやメソッド名が重複しているものがある 私の場合は、設計したDBにassociationというカラムがあった ことが原因。

attribute_methods.rbのコードを読んでみた

github.com

確かにチェックしている。

def instance_method_already_implemented?(method_name)
  if dangerous_attribute_method?(method_name)
    raise DangerousAttributeError, "#{method_name} is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name."
  end
# A method name is 'dangerous' if it is already (re)defined by Active Record, but
# not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
def dangerous_attribute_method?(name) # :nodoc:
  method_defined_within?(name, Base)
end

何が重複しているのか調査

binding.pryで停止して、ActiveRecord::Base のメソッドやインスタンス変数を確認してみる。

ActiveRecord::Baseのメソッド一覧

> ActiveRecord::Base.methods
=> [:_rollback_callbacks,
 :_commit_callbacks,
 :_before_commit_callbacks,
 :_commit_callbacks=,
 :_rollback_callbacks=,
 :_before_commit_callbacks=,
 :_before_commit_without_transaction_enrollment_callbacks,
 :_before_commit_without_transaction_enrollment_callbacks=,
 :_commit_without_transaction_enrollment_callbacks,
 :_commit_without_transaction_enrollment_callbacks=,
 :_rollback_without_transaction_enrollment_callbacks,
 :_rollback_without_transaction_enrollment_callbacks=,
 :aggregate_reflections,
 :_ransackers?,
 :_ransack_aliases?,
 :_reflections=,
 :aggregate_reflections=,
 :_validators,
 :_validators=,
 :before_destroy,
 :after_destroy,
 :before_update,
 :after_update,
 :_attr_readonly,
 :_attr_readonly=,
 :_attr_readonly?,
 :primary_key_prefix_type,
 :timestamped_migrations,
 :default_timezone,
 :default_timezone=,
 :table_name_prefix?,
 :primary_key_prefix_type=,
 :table_name_suffix=,
 :table_name_prefix=,
 :table_name_suffix,
 :schema_migrations_table_name=,
 :schema_migrations_table_name?,
 :table_name_suffix?,
 :pluralize_table_names=,
 :internal_metadata_table_name=,
 :store_full_sti_class,
 :internal_metadata_table_name?,
 :time_zone_aware_types,
 :pluralize_table_names?,
 :_reflections?,
 :aggregate_reflections?,
 :time_zone_aware_types=,
 :local_stored_attributes,
 :store_full_sti_class?,
 :store_full_sti_class=,
 :default_scopes,
 :default_scope_override,
 :local_stored_attributes=,
 :default_scope_override=,
 :schema_migrations_table_name,
 :internal_metadata_table_name,
 :default_scopes=,
 :_ransackers=,
 :_ransack_aliases=,
 :supports_import?,
 :supports_on_duplicate_key_update?,
 :bulk_import,
 :attribute_type_decorations,
 :attribute_type_decorations=,
 :establish_connection_with_activerecord_import,
 :establish_connection_without_activerecord_import,
 :supports_setting_primary_key_of_imported_objects?,
 :import_helper,
 :bulk_import!,
 :import!,
 :__callbacks,
 :cache_timestamp_format?,
 :cache_timestamp_format=,
 :cache_versioning?,
 :import_with_validations,
 :import_without_validations_or_callbacks,
 :maintain_test_schema,
 :maintain_test_schema=,
 :attributes_to_define_after_schema_loads,
 :attributes_to_define_after_schema_loads=,
 :before_create,
 :_reflections,
 :_validate_callbacks,
 :_validate_callbacks=,
 :_validators?,
 :verbose_query_logs,
 :verbose_query_logs=,
 :time_zone_aware_attributes,
 :time_zone_aware_attributes=,
 :after_create,
 :connection_handler,
 :attributes_to_define_after_schema_loads?,
 :warn_on_records_fetched_greater_than,
 :configurations,
 :configurations=,
 :attribute_type_decorations?,
 :lock_optimistically,
 :establish_connection,
 :lock_optimistically?,
 :lock_optimistically=,
 :_validation_callbacks,
 :_validation_callbacks=,
 :_initialize_callbacks,
 :_initialize_callbacks=,
 :_find_callbacks,
 :_find_callbacks=,
 :after_find,
 :_touch_callbacks,
 :_touch_callbacks=,
 :after_touch,
 :_save_callbacks,
 :_save_callbacks=,
 :before_save,
 :around_save,
 :after_save,
 :_create_callbacks,
 :_create_callbacks=,
 :around_create,
 :_update_callbacks,
 :__callbacks=,
 :_update_callbacks=,
 :around_update,
 :_destroy_callbacks,
 :_destroy_callbacks=,
 :around_destroy,
 :defined_enums,
 :defined_enums=,
 :__callbacks?,
 :attribute_aliases?,
 :attribute_method_matchers?,
 :logger,
 :skip_time_zone_conversion_for_attributes,
 :skip_time_zone_conversion_for_attributes?,
 :skip_time_zone_conversion_for_attributes=,
 :time_zone_aware_types?,
 :partial_writes,
 :partial_writes?,
 :record_timestamps,
 :partial_writes=,
 :defined_enums?,
 :record_timestamps?,
 :record_timestamps=,
 :cache_timestamp_format,
 :schema_format,
 :error_on_ignored_order,
 :dump_schema_after_migration,
 :dump_schemas,
 :default_connection_handler,
 :connection_handler=,
 :default_connection_handler=,
 :index_nested_attribute_errors,
 :allow_unsafe_raw_sql,
 :table_name_prefix,
 :_ransackers,
 :after_initialize,
 :logger=,
 :attribute_aliases,
 :attribute_method_matchers,
 :import,
 :attribute_aliases=,
 :include_root_in_json,
 :schema_format=,
 :error_on_ignored_order=,
 :index_nested_attribute_errors=,
 :allow_unsafe_raw_sql=,
 :nested_attributes_options,
 :timestamped_migrations=,
 :dump_schema_after_migration=,
 :synchronize,
 :dump_schemas=,
 :warn_on_records_fetched_greater_than=,
 :attribute_method_matchers=,
 :nested_attributes_options=,
 :default_connection_handler?,
 :belongs_to_required_by_default,
 :belongs_to_required_by_default=,
 :cache_versioning,
 :cache_versioning=,
 :nested_attributes_options?,
 :include_root_in_json?,
 :include_root_in_json=,
 :_ransack_aliases,
 :pluralize_table_names,
 :find_by_sql,
 :devise,
 :devise_modules_hook!,
 :decorator_class,
 :===,
 :decorator_class?,
 :decorate,
 :ransack_alias,
 :ransacker,
 :ransortable_attributes,
 :ransack,
 :ransackable_attributes,
 :ransackable_associations,
 :ransackable_scopes,
 :search,
 :inherited,
 :acts_as_list,
 :to_adapter,
 :suppress,
 :has_secure_token,
 :generate_unique_secure_token,
 :store_accessor,
 :store,
 :_store_accessors_module,
 :stored_attributes,
 :_reflect_on_association,
 :reflections,
 :reflect_on_all_aggregations,
 :reflect_on_all_associations,
 :clear_reflections_cache,
 :reflect_on_all_autosave_associations,
 :reflect_on_aggregation,
 :reflect_on_association,
 :no_touching,
 :after_commit,
 :before_commit,
 :before_commit_without_transaction_enrollment,
 :after_create_commit,
 :after_update_commit,
 :after_destroy_commit,
 :transaction,
 :after_commit_without_transaction_enrollment,
 :after_rollback_without_transaction_enrollment,
 :after_rollback,
 :composed_of,
 :accepts_nested_attributes_for,
 :has_secure_password,
 :has_one,
 :belongs_to,
 :has_and_belongs_to_many,
 :has_many,
 :serialize,
 :reset_primary_key,
 :primary_key,
 :quoted_primary_key,
 :instance_method_already_implemented?,
 :dangerous_attribute_method?,
 :get_primary_key,
 :primary_key=,
 :enforce_raw_sql_whitelist,
 :initialize_generated_modules,
 :has_attribute?,
 :column_for_attribute,
 :define_attribute_methods,
 :undefine_attribute_methods,
 :method_defined_within?,
 :dangerous_class_method?,
 :class_method_defined_within?,
 :attribute_method?,
 :attribute_names,
 :attribute_method_prefix,
 :attribute_method_suffix,
 :attribute_method_affix,
 :attribute_alias?,
 :attribute_alias,
 :define_attribute_method,
 :alias_attribute,
 :before_validation,
 :after_validation,
 :locking_column,
 :locking_column=,
 :update_counters,
 :reset_locking_column,
 :locking_enabled?,
 :decorate_attribute_type,
 :decorate_matching_attribute_types,
 :attribute,
 :define_attribute,
 :decrement_counter,
 :reset_counters,
 :increment_counter,
 :validates_uniqueness_of,
 :validates_length_of,
 :validates_size_of,
 :validates_absence_of,
 :validates_associated,
 :validates_presence_of,
 :validates_inclusion_of,
 :validates_numericality_of,
 :validates_confirmation_of,
 :validates_acceptance_of,
 :validates_format_of,
 :validates_exclusion_of,
 :normalize_callback_params,
 :set_callback,
 :__update_callbacks,
 :get_callbacks,
 :set_callbacks,
 :skip_callback,
 :define_callbacks,
 :reset_callbacks,
 :define_model_callbacks,
 :validates,
 :validators_on,
 :validates_each,
 :validates!,
 :validates_with,
 :clear_validators!,
 :validators,
 :validate,
 :to_param,
 :_to_partial_path,
 :sanitize_sql,
 :sanitize_sql_for_conditions,
 :sanitize_sql_array,
 :sanitize_sql_for_assignment,
 :sanitize_sql_hash_for_assignment,
 :sanitize_sql_for_order,
 :sanitize_sql_like,
 :default_scoped,
 :scope_for_association,
 :scope,
 :default_extensions,
 :all,
 :unscoped,
 :scope_attributes?,
 :before_remove_const,
 :current_scope,
 :current_scope=,
 :scope_attributes,
 :abstract_class=,
 :base_class,
 :descends_from_active_record?,
 :finder_needs_type_condition?,
 :new,
 :sti_name,
 :compute_type,
 :abstract_class,
 :polymorphic_name,
 :abstract_class?,
 :attribute_types,
 :inheritance_column,
 :columns,
 :inheritance_column=,
 :ignored_columns,
 :ignored_columns=,
 :initialize_load_schema_monitor,
 :columns_hash,
 :reset_table_name,
 :table_name=,
 :reset_column_information,
 :full_table_name_prefix,
 :full_table_name_suffix,
 :_default_attributes,
 :yaml_encoder,
 :attributes_builder,
 :table_name,
 :reset_sequence_name,
 :sequence_name=,
 :next_sequence_value,
 :type_for_attribute,
 :column_defaults,
 :content_columns,
 :sequence_name,
 :protected_environments,
 :protected_environments=,
 :quoted_table_name,
 :table_exists?,
 :column_names,
 :prefetch_primary_key?,
 :readonly_attributes,
 :attr_readonly,
 :destroy,
 :update,
 :create!,
 :instantiate,
 :delete,
 :_insert_record,
 :create,
 :_update_record,
 :_delete_record,
 :initialize_find_by_cache,
 :generated_association_methods,
 :inspect,
 :allocate,
 :predicate_builder,
 :arel_attribute,
 :arel_table,
 :find_by,
 :find_by!,
 :find,
 :type_caster,
 :collection_cache_key,
 :relation_delegate_class,
 :initialize_relation_delegate_cache,
 :enum,
 :collecting_queries_for_explain,
 :exec_explain,
 :i18n_scope,
 :lookup_ancestors,
 :human_attribute_name,
 :in_batches,
 :limit,
 :left_joins,
 :left_outer_joins,
 :find_or_initialize_by,
 :extending,
 :rewhere,
 :ids,
 :create_with,
 :reorder,
 :readonly,
 :unscope,
 :except,
 :offset,
 :average,
 :delete_all,
 :preload,
 :sum,
 :last,
 :count_by_sql,
 :calculate,
 :joins,
 :third,
 :fourth,
 :fifth,
 :forty_two,
 :third_to_last,
 :second_to_last,
 :update_all,
 :group,
 :includes,
 :none,
 :order,
 :eager_load,
 :lock,
 :from,
 :exists?,
 :where,
 :references,
 :having,
 :second,
 :count,
 :merge,
 :select,
 :or,
 :minimum,
 :first,
 :any?,
 :one?,
 :none?,
 :many?,
 :distinct,
 :pluck,
 :maximum,
 :take!,
 :first!,
 :last!,
 :second!,
 :take,
 :fourth!,
 :fifth!,
 :third!,
 :forty_two!,
 :third_to_last!,
 :second_to_last!,
 :first_or_create,
 :first_or_create!,
 :first_or_initialize,
 :find_or_create_by,
 :find_or_create_by!,
 :destroy_all,
 :find_each,
 :find_in_batches,
 :uncached,
 :cache,
 :connection_config,
 :clear_all_connections!,
 :connection,
 :connection_pool,
 :retrieve_connection,
 :remove_connection,
 :postgresql_connection,
 :connected?,
 :clear_cache!,
 :clear_reloadable_connections!,
 :clear_active_connections!,
 :flush_idle_connections!,
 :connection_specification_name,
 :connection_specification_name=,
 :descendants,
 :direct_descendants,
 :benchmark,
 :model_name,
 :yaml_tag,
 :method_added,
 :json_creatable?,
 :subclasses,
 :superclass,
 :class_attribute,
 :to_template,
 :to_v8,
 :weakcell,
 :reachable?,
 :parents,
 :autoload,
 :autoload?,
 :anonymous?,
 :thread_mattr_reader,
 :included_modules,
 :include?,
 :name,
 :ancestors,
 :attr,
 :attr_reader,
 :attr_writer,
 :attr_accessor,
 :instance_methods,
 :public_instance_methods,
 :protected_instance_methods,
 :private_instance_methods,
 :constants,
 :const_get,
 :const_set,
 :const_defined?,
 :class_variables,
 :remove_class_variable,
 :class_variable_get,
 :class_variable_set,
 :class_variable_defined?,
 :public_constant,
 :private_constant,
 :deprecate_constant,
 :singleton_class?,
 :class_exec,
 :module_eval,
 :class_eval,
 :include,
 :undef_method,
 :alias_method,
 :remove_method,
 :module_exec,
 :<,
 :protected_method_defined?,
 :>,
 :public_class_method,
 :method_defined?,
 :public_method_defined?,
 :private_method_defined?,
 :instance_method,
 :private_class_method,
 :define_method,
 :remove_possible_method,
 :thread_cattr_reader,
 :thread_mattr_writer,
 :cattr_accessor,
 :thread_mattr_accessor,
 :delegate_missing_to,
 :public_instance_method,
 :attr_internal_reader,
 :attr_internal_writer,
 :attr_internal_accessor,
 :attr_internal,
 :silence_redefinition_of_method,
 :redefine_singleton_method,
 :delegate,
 :thread_cattr_writer,
 :class_name,
 :thread_cattr_accessor,
 :redefine_method,
 :remove_possible_singleton_method,
 :pretty_print_cycle,
 :context,
 :<=>,
 :<=,
 :>=,
 :==,
 :method_visibility,
 :memoized,
 :namespace_name,
 :parent,
 :shared_examples,
 :shared_context,
 :shared_examples_for,
 :mattr_reader,
 :parent_name,
 :freeze,
 :prepend,
 :mattr_writer,
 :cattr_writer,
 :cattr_reader,
 :mattr_accessor,
 :describe,
 :xdescribe,
 :xcontext,
 :fdescribe,
 :fcontext,
 :example_group,
 :to_s,
 :deprecate,
 :pretty_print,
 :rake_extension,
 :const_missing,
 :guess_for_anonymous,
 :unloadable,
 :concerning,
 :concern,
 :to_json,
 :in?,
 :presence_in,
 :to_yaml,
 :dclone,
 :acts_like?,
 :html_safe?,
 :deep_dup,
 :duplicable?,
 :with_options,
 :`,
 :presence,
 :blank?,
 :as_json,
 :present?,
 :to_query,
 :pry,
 :__binding__,
 :bullet_key,
 :instance_values,
 :instance_variable_names,
 :primary_key_value,
 :require_dependency,
 :require_or_load,
 :load_dependency,
 :pretty_print_inspect,
 :pretty_print_instance_variables,
 :load_all,
 :load_rel,
 :autoload_all,
 :autoload_rel,
 :require_all,
 :require_rel,
 :to_ruby,
 :try!,
 :try,
 :instance_variable_set,
 :instance_variable_defined?,
 :remove_instance_variable,
 :instance_of?,
 :kind_of?,
 :is_a?,
 :tap,
 :instance_variable_get,
 :public_methods,
 :instance_variables,
 :method,
 :public_method,
 :singleton_method,
 :define_singleton_method,
 :public_send,
 :extend,
 :to_enum,
 :enum_for,
 :remote_byebug,
 :byebug,
 :debugger,
 :gem,
 :suppress_warnings,
 :__called_from__,
 :=~,
 :!~,
 :expirable_memoize,
 :eql?,
 :respond_to?,
 :pretty_inspect,
 :object_id,
 :send,
 :display,
 :nil?,
 :hash,
 :class,
 :singleton_class,
 :clone,
 :dup,
 :itself,
 :yield_self,
 :taint,
 :untaint,
 :tainted?,
 :untrusted?,
 :untrust,
 :frozen?,
 :trust,
 :singleton_methods,
 :methods,
 :private_methods,
 :protected_methods,
 :!,
 :equal?,
 :instance_eval,
 :instance_exec,
 :!=,
 :__id__,
 :__send__]
(END)

ActiveRecord::Baseのインスタンス変数一覧

> ActiveRecord::Base.instance_variables
=> [:@protected_environments,
 :@inheritance_column,
 :@explicit_inheritance_column,
 :@ignored_columns,
 :@load_schema_monitor,
 :@generated_attribute_methods,
 :@attribute_methods_generated,
 :@generated_association_methods,
 :@connection_specification_name]

ActiveRecord::Baseのクラス変数一覧

> ActiveRecord::Base.class_variables
=> [:@@logger,
 :@@verbose_query_logs,
 :@@default_timezone,
 :@@schema_format,
 :@@error_on_ignored_order,
 :@@allow_unsafe_raw_sql,
 :@@timestamped_migrations,
 :@@dump_schema_after_migration,
 :@@dump_schemas,
 :@@warn_on_records_fetched_greater_than,
 :@@maintain_test_schema,
 :@@belongs_to_required_by_default,
 :@@primary_key_prefix_type,
 :@@time_zone_aware_attributes,
 :@@index_nested_attribute_errors,
 :@@configurations]

ActiveRecord::Baseのインスタンスメソッド一覧

> ActiveRecord::Base.instance_methods
=> [:save,
 :save!,
 :_run_save_callbacks,
 :_save_callbacks,
 :_find_callbacks,
 :_run_create_callbacks,
 :_create_callbacks,
 :_rollback_callbacks,
 :_commit_callbacks,
 :_run_update_callbacks,
 :_update_callbacks,
 :_before_commit_callbacks,
 :_run_destroy_callbacks,
 :_destroy_callbacks,
 :_before_commit_without_transaction_enrollment_callbacks,
 :defined_enums,
 :attribute_aliases?,
 :__callbacks?,
 :_rollback_without_transaction_enrollment_callbacks,
 :attribute_method_matchers?,
 :logger,
 :_commit_without_transaction_enrollment_callbacks,
 :aggregate_reflections,
 :_ransackers?,
 :_ransack_aliases?,
 :validation_context,
 :_validators,
 :skip_time_zone_conversion_for_attributes,
 :skip_time_zone_conversion_for_attributes?,
 :time_zone_aware_types?,
 :_run_validate_callbacks,
 :partial_writes,
 :primary_key_prefix_type,
 :partial_writes?,
 :record_timestamps,
 :timestamped_migrations,
 :default_timezone,
 :table_name_prefix?,
 :defined_enums?,
 :table_name_suffix?,
 :time_zone_aware_types,
 :table_name_suffix,
 :record_timestamps?,
 :record_timestamps=,
 :pluralize_table_names?,
 :column_for_attribute,
 :store_full_sti_class,
 :_run_validation_callbacks,
 :cache_timestamp_format,
 :schema_format,
 :error_on_ignored_order,
 :dump_schema_after_migration,
 :dump_schemas,
 :_reflections?,
 :default_connection_handler,
 :aggregate_reflections?,
 :index_nested_attribute_errors,
 :allow_unsafe_raw_sql,
 :store_full_sti_class?,
 :default_scopes,
 :default_scope_override,
 :_ransackers=,
 :_ransack_aliases=,
 :table_name_prefix,
 :_run_initialize_callbacks,
 :_ransackers,
 :_run_find_callbacks,
 :attribute_aliases,
 :attribute_method_matchers,
 :model_name,
 :include_root_in_json,
 :__callbacks,
 :nested_attributes_options,
 :synchronize,
 :cache_timestamp_format?,
 :cache_versioning?,
 :default_connection_handler?,
 :cache_versioning,
 :_reflections,
 :_validate_callbacks,
 :_validators?,
 :verbose_query_logs,
 :nested_attributes_options?,
 :time_zone_aware_attributes,
 :type_for_attribute,
 :warn_on_records_fetched_greater_than,
 :lock_optimistically,
 :include_root_in_json?,
 :_ransack_aliases,
 :pluralize_table_names,
 :lock_optimistically?,
 :_run_before_commit_without_transaction_enrollment_callbacks,
 :_run_before_commit_callbacks,
 :_initialize_callbacks,
 :_validation_callbacks,
 :_run_commit_without_transaction_enrollment_callbacks,
 :_run_commit_callbacks,
 :_run_touch_callbacks,
 :_touch_callbacks,
 :_run_rollback_callbacks,
 :_run_rollback_without_transaction_enrollment_callbacks,
 :decorated_with?,
 :decorator_class,
 :decorated?,
 :decorator_class?,
 :decorate,
 :applied_decorators,
 :==,
 :to_global_id,
 :to_signed_global_id,
 :to_gid,
 :to_gid_param,
 :to_sgid,
 :to_sgid_param,
 :serializable_hash,
 :from_json,
 :as_json,
 :read_attribute_for_serialization,
 :no_touching?,
 :touch_later,
 :touch,
 :destroy,
 :add_to_transaction,
 :transaction,
 :rollback_active_record_state!,
 :with_transaction_returning_status,
 :before_committed!,
 :committed!,
 :rolledback!,
 :reload,
 :_destroy,
 :marked_for_destruction?,
 :mark_for_destruction,
 :destroyed_by_association=,
 :changed_for_autosave?,
 :destroyed_by_association,
 :association,
 :association_cached?,
 :attribute_change_to_be_saved,
 :changes_to_save,
 :changed_attribute_names_to_save,
 :will_save_change_to_attribute?,
 :attributes_in_database,
 :attribute_in_database,
 :has_changes_to_save?,
 :saved_change_to_attribute,
 :saved_changes?,
 :saved_changes,
 :saved_change_to_attribute?,
 :attribute_before_last_save,
 :attribute_changed_in_place?,
 :changed,
 :changed_attributes,
 :attribute_changed?,
 :attribute_previously_changed?,
 :restore_attributes,
 :clear_attribute_changes,
 :previous_changes,
 :clear_changes_information,
 :changed?,
 :attribute_was,
 :changes_applied,
 :changes,
 :id_before_type_cast,
 :id_in_database,
 :id,
 :id=,
 :id?,
 :to_key,
 :id_was,
 :query_attribute,
 :attributes_before_type_cast,
 :read_attribute_before_type_cast,
 :_write_attribute,
 :write_attribute,
 :_read_attribute,
 :read_attribute,
 :attributes,
 :has_attribute?,
 :attribute_for_inspect,
 :[],
 :attribute_present?,
 :[]=,
 :accessed_fields,
 :respond_to?,
 :attribute_names,
 :respond_to_without_attributes?,
 :method_missing,
 :attribute_missing,
 :with_lock,
 :lock!,
 :locking_enabled?,
 :valid?,
 :validate,
 :validates_inclusion_of,
 :validates_numericality_of,
 :validates_confirmation_of,
 :validates_acceptance_of,
 :validates_length_of,
 :validates_format_of,
 :validates_size_of,
 :validates_exclusion_of,
 :validates_absence_of,
 :validates_presence_of,
 :run_callbacks,
 :read_attribute_for_validation,
 :errors,
 :invalid?,
 :validates_with,
 :validate!,
 :report_validation_errors_to_rollbar,
 :cache_key_with_version,
 :cache_version,
 :to_param,
 :cache_key,
 :to_partial_path,
 :to_model,
 :attributes=,
 :assign_attributes,
 :populate_with_current_scope_attributes,
 :initialize_internals_callback,
 :increment!,
 :toggle!,
 :toggle,
 :update!,
 :update_attribute,
 :update_attributes!,
 :delete,
 :update_column,
 :update_columns,
 :update_attributes,
 :new_record?,
 :destroyed?,
 :update,
 :becomes,
 :becomes!,
 :increment,
 :decrement,
 :persisted?,
 :decrement!,
 :destroy!,
 :encode_with,
 :connection_handler,
 :<=>,
 :freeze,
 :hash,
 :pretty_print,
 :inspect,
 :readonly!,
 :slice,
 :init_with,
 :eql?,
 :frozen?,
 :readonly?,
 :to_json,
 :in?,
 :presence_in,
 :to_yaml,
 :dclone,
 :acts_like?,
 :html_safe?,
 :deep_dup,
 :duplicable?,
 :with_options,
 :`,
 :presence,
 :blank?,
 :present?,
 :to_query,
 :pry,
 :__binding__,
 :bullet_key,
 :instance_values,
 :instance_variable_names,
 :primary_key_value,
 :require_dependency,
 :unloadable,
 :require_or_load,
 :load_dependency,
 :pretty_print_inspect,
 :pretty_print_cycle,
 :pretty_print_instance_variables,
 :load_all,
 :load_rel,
 :autoload_all,
 :autoload_rel,
 :require_all,
 :require_rel,
 :to_ruby,
 :to_v8,
 :try!,
 :try,
 :instance_variable_set,
 :instance_variable_defined?,
 :remove_instance_variable,
 :instance_of?,
 :kind_of?,
 :is_a?,
 :tap,
 :instance_variable_get,
 :public_methods,
 :instance_variables,
 :method,
 :public_method,
 :singleton_method,
 :define_singleton_method,
 :public_send,
 :class_eval,
 :extend,
 :to_enum,
 :enum_for,
 :remote_byebug,
 :byebug,
 :debugger,
 :gem,
 :suppress_warnings,
 :===,
 :__called_from__,
 :=~,
 :!~,
 :expirable_memoize,
 :pretty_inspect,
 :object_id,
 :send,
 :to_s,
 :display,
 :nil?,
 :class,
 :singleton_class,
 :clone,
 :dup,
 :itself,
 :yield_self,
 :taint,
 :untaint,
 :tainted?,
 :untrusted?,
 :untrust,
 :trust,
 :singleton_methods,
 :methods,
 :private_methods,
 :protected_methods,
 :!,
 :equal?,
 :instance_eval,
 :instance_exec,
 :!=,
 :__id__,
 :__send__]
(END)

対処

自分が設計したDBのカラム名を変更する。 私の場合は、設計したDBにassociationというカラムがあったため、重複しないカラム名に変更した。

おわりに

非常に勉強になりました。Railsのソースを読んで、pryで実際の値を確認して調査するというステップは、障害解析にとても有効なので、今後も継続したい。

【ActiveRecord5.2.0】JoinDependencyのコンストラクタの引数の仕様がいろいろ変わっている事に気づかず、3日くらいハマった話。#Rails #ActiveRecord

f:id:yokoyantech:20181005130407p:plain

はじめに

Rails5.1.1で動かしていたプログラムを、Rails5.2.0で動かしたら、JoinDependency.newでエラーが発生した。 いろいろ回り道して調べた結果、ここ3日くらいハマってしまったのでメモ。

発生したエラー

wrong number of arguments (given 3, expected 4)

原因

ActiveRecord 5.1.1と、ActiveRecord 5.2.0では、コンストラクタの引数の仕様が変わっている ため。 なん・・・だと・・・。

ActiveRecord 5.1.1

Class: ActiveRecord::Associations::JoinDependency — Documentation for activerecord (5.1.1)

initialize(base, associations, joins, eager_loading: true)

ActiveRecord 5.2.0

Class: ActiveRecord::Associations::JoinDependency — Documentation for activerecord (5.2.0)

initialize(base, table, associations, alias_tracker)

うおー。変わってるー!tableってなんじゃい! 第2引数のtableには、Userオブジェクトなどを入れると動く。

ActiveRecord 5.2.1

ちなみに、最新版の5.2.1も調べてみた。コンストラクタの引数が4つから3つになってる!!

Class: ActiveRecord::Associations::JoinDependency — Documentation for activerecord (5.2.1)

initialize(base, table, associations)

修正方法

ひとまずプロジェクトでは、ActiveRecord 5.2.0を使う。 JoinDependency.new使用時に、第2引数を追加。

修正前

join_dependency = ::ActiveRecord::Associations::JoinDependency.new(klass, [], [])

修正後

join_dependency = ::ActiveRecord::Associations::JoinDependency.new(klass, self.base.base_klass, [], [])

おわりに

Railsだけでなく、ActiveRecordのソースもちゃんと読んだほうがいいなと思いました。 反省。

【VS Code】Failed to start Solargraph: Unable to load the EventMachine C extensionのエラーが出たときの対処方法 #Solargraph

f:id:yokoyantech:20181001130424p:plain

はじめに

Visual StudioでSolargraphが動かなくなったので、解決するまでをメモ。

実行環境

  • Windows10 64bit Pro
  • Vivual Studio Code 1.27.2
  • Ruby 2.4.4

発生したエラー

Failed to start Solargraph: Unable to load the EventMachine C extension; To use the pure-ruby reactor, require 'em/pure_ruby' Unable to load the EventMachine C extension; To use the pure-ruby reactor, require 'em/pure_ruby' 
C:/Ruby24/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- 2.4/rubyeventmachine (LoadError) from C:/Ruby24/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require' from
C:/Ruby24/lib/ruby/gems/2.4.0/gems/eventmachine-1.2.7-x86-mingw32/lib/rubyeventmachine.rb:2:in `<top (required)>' from C:/Ruby24/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:133:in `require' from
C:/Ruby24/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:133:in `rescue in require' from C:/Ruby24/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:39:in `require' from C:/Ruby24/lib/ruby/gems/2.4.0/gems/eventmachine-1.2.7-x86-mingw32/lib/eventmachine.rb:8:in `<top (required)>' from C:/Ruby24/lib/ruby/2.4.0/rubygems/core_ext/ke...

事象の確認

solargraph helpが動かない。

$ solargraph help
Unable to load the EventMachine C extension; To use the pure-ruby reactor, require 'em/pure_ruby'
Unable to load the EventMachine C extension; To use the pure-ruby reactor, require 'em/pure_ruby'
C:/Ruby24/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- 2.4/rubyeventmachine (LoadError)
        from C:/Ruby24/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'

このブログ記事と同じ状況。

unirt.hatenablog.com

解決方法

  • eventmachineのアンインストール
$ gem uninstall eventmachine
  • 再インストール
$ gem install eventmachine --platform ruby
  • VSCodeを再起動
  • SolargraphをUpdateする

動作確認

image

【読書】36歳にして初めてリーダブルコードを読んで猛省している件。プログラマはもちろん経営者にも読んで欲しい1冊

はじめに

同僚に薦められて、リーダブルコードを読み始めました。

リーダブルコードとは?

わかりやすいプログラムを書くための原理原則が書いてある本です。

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

  • 作者: Dustin Boswell,Trevor Foucher,須藤功平,角征典
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2012/06/23
  • メディア: 単行本(ソフトカバー)
  • 購入: 68人 クリック: 1,802回
  • この商品を含むブログ (140件) を見る

プログラムに関わる全ての人が読むべき本

まだ読み始めたばかりですが、これまで自分が書いていたコードがいかに汚いものであるかということを実感しました。やっぱり我流はよくないです。全てのプログラマが読むべき古典的名作だと思います。 特に言語に依存することもなく、どんな言語であっても使える原理原則が書いてあります。

コードは理解しやすくなければならない。

コードは他の人が最短時間で理解できるように書かなければならない。 「理解する」というのは、変更を加えたりバグを見つけたりできるという意味だ。 「他の人」というのは、自分のコードに見覚えのない6ヶ月後の「君自身」かもしれない。

最も読みやすいコードは、何も書かれていないコードだ。 冒険。興奮。ジェダイはそんなものは求めておらん。-ヨーダ

また、プログラマだけでなく、自社製品を作る経営者や、リーダーの人たちも読むと、リファクタリングの重要性がよく分かるのでおすすめです。リファクタリングは直接お客様にメリットがないからやらないという方針を経営者や上司が行うと、現場は萎えます。下手するとエンジニアが辞めるかもしれません。結果、自社製品の開発速度は下がり、誰も手が出せない製品が誕生します。一方で、社長から「定期的にリファクタリングしてる?」と言われるとものすごく嬉しいと思います。

ぜひ仕事で使いたい。いや、使うべき。

Githubのプルリクエストの指摘事項のほとんどが、リーダブルコードの中に書いてあるものばかりだったので猛省しています。set_hogeDataみたいなメソッド名の付け方をやってしまいがちなのですが、曖昧すぎて良くないということを学びました。早速自分の書いたPythonのコードを、リーダブルコードに従って、がっつりリファクタリングしました。薦めてくれた同僚に感謝です。プロダクトチームの中で、リーダブルコードの内容が共通認識として浸透できるように、原理原則を身につけたいと思います。

おわりに

本の存在はずっと前から知っていたのですが、お恥ずかしながらこの年になるまで読んだことがありませんでした。プログラムに関する古典的名作はまだまだあるので、これからもたくさんの本を読んで学びたいと思います。

【Python+Psycopg2】PostgreSQLからEXISTSを使ってデータの存在チェックメソッドを作る方法

f:id:yokoyantech:20180717175613p:plain

実行環境

  • AWS Lambda
  • Python3.6
  • PostgreSQL9.6.6
  • psycopg2

やりたいこと

  • existsでデータの有無を確認
  • 結果をBooleanで返却したい

解決方法

fetchone()を使う。公式ドキュメントは以下。

The cursor class — Psycopg 2.7.5 documentation

実装例

def is_exists(cur, fuga_no):
    cur.execute(
        "SELECT EXISTS (SELECT * FROM public.hoge WHERE fuga_no = %s)" % fuga_no)
    return cur.fetchone() is not None

参考情報

stackoverflow.com