はじめに
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.
参考情報
これは、ActiveRecordで利用されているプロパティやメソッド名とDBのカラム名が同じ名前の場合に出力されるエラーのようです。 自分の環境では「model_name」や「changed」といったものがダメでした。他にも「hash」や「save」といったもの使えないようです。
正確に言うと hash だけじゃなくて ActiveRecord::Base に実装されているメソッド名は基本的にダメっていう理解で正しいと思う.例えば save もそう.
原因
自分が設計したDBのカラム名と、ActiveRecordで利用されているプロパティやメソッド名が重複しているものがある
私の場合は、設計したDBにassociation
というカラムがあった ことが原因。
attribute_methods.rbのコードを読んでみた
確かにチェックしている。
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で実際の値を確認して調査するというステップは、障害解析にとても有効なので、今後も継続したい。