Database definition with nested attributes and HABTM - ruby-on-rails

I am trying to track GPS satellites as they cross the sky. I receive 'SKY' messages every 5 seconds, containing location and signal strength data for each satellite currently visible. The database contains tables for 'skies', 'sats', 'tracks' and 'points'. The idea is that each sky received will add a location point to each of its satellite's track. Schema is...
create_table "points", force: :cascade do |t|
t.bigint "track_id"
t.integer "az"
t.integer "el"
t.integer "ss"
t.boolean "used"
t.boolean "duplicate"
t.integer "PRN"
t.bigint "sky_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["PRN"], name: "index_points_on_PRN"
t.index ["created_at"], name: "index_points_on_created_at"
t.index ["sky_id"], name: "index_points_on_sky_id"
t.index ["track_id"], name: "index_points_on_track_id"
end
create_table "sats", force: :cascade do |t|
t.integer "PRN"
t.datetime "created_at", precision: 6
t.datetime "updated_at", precision: 6
t.index ["PRN"], name: "index_sats_on_PRN"
end
create_table "sats_skies", id: false, force: :cascade do |t|
t.bigint "sky_id", null: false
t.bigint "sat_id", null: false
t.index ["sat_id", "sky_id"], name: "index_sats_skies_on_sat_id_and_sky_id"
t.index ["sky_id", "sat_id"], name: "index_sats_skies_on_sky_id_and_sat_id"
end
create_table "skies", force: :cascade do |t|
t.string "klass"
t.string "tag"
t.string "device"
t.float "time"
t.float "xdop"
t.float "ydop"
t.float "vdop"
t.float "tdop"
t.float "hdop"
t.float "pdop"
t.float "gdop"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["created_at"], name: "index_skies_on_created_at"
end
create_table "tracks", force: :cascade do |t|
t.bigint "sat_id"
t.index ["sat_id"], name: "index_tracks_on_sat_id"
end
The model definitions are...
class Sky < ApplicationRecord
include ActionView::Helpers::NumberHelper
has_and_belongs_to_many :sats, inverse_of: :sky, dependent: :destroy
has_many :points, inverse_of: :sky
accepts_nested_attributes_for :sats, allow_destroy: true
accepts_nested_attributes_for :points, allow_destroy: true
end
class Sat < ApplicationRecord
has_and_belongs_to_many :skies, inverse_of: :sat, autosave: true
has_one :track, inverse_of: :sat
accepts_nested_attributes_for :skies, allow_destroy: true
accepts_nested_attributes_for :track, allow_destroy: true
end
class Track < ApplicationRecord
has_many :points, inverse_of: :track
belongs_to :sat, inverse_of: :track
accepts_nested_attributes_for :points, allow_destroy: true
end
class Point < ApplicationRecord
belongs_to :sky, inverse_of: :point #, optional: true
belongs_to :track, inverse_of: :point #, optional: true
end
When a sky message is received, it checks the previous sky message to see which of it's satellites also existed there. For those found, the point is just added to that satellite's track table. If the satellite was not visible in the last sky, a new sat record is created, and its location 'point' is added to the new sat's track.
Note that the point record has foreign keys for both the track, and the sky records.
Initially, I had all this working, but I was creating the sky record, then creating the sat/track records (if needed), then saving the point. A power failure while processing a sky message caused the database to contain a sat/track with no points. I realize I could just surround all this processing with a transaction block, but thought a cleaner solution would be to create all the various components for a sky message in memory and when complete save the whole batch with a single new_sky.save.
But try as I may, I don't seem to be able to get the proper combination 'reverse_of', 'nested_attributes' and other definition attributes to successfully save the results. With everything configured as listed here, I am currently getting the following while processing the first satellite in the first sky message received...
D, [2020-05-03 10:37:32.410281000 -0500 CDT#83744] DEBUG -- GpsComms: ************* This sat (#8) not found in previous SKY, create new *************
E, [2020-05-03 10:37:32.436055000 -0500 CDT#83744] ERROR -- GpsComms: Sat Processing Failed
E, [2020-05-03 10:37:32.436454000 -0500 CDT#83744] ERROR -- GpsComms: {:Rescue=>"#<ActiveRecord::InverseOfAssociationNotFoundError: Could not find the inverse association for track (:point in Track)>"}
E, [2020-05-03 10:37:32.436786000 -0500 CDT#83744] ERROR -- GpsComms: Could not find the inverse association for track (:point in Track) - (ActiveRecord::InverseOfAssociationNotFoundError)
With other combinations of options (reverse_of:, optional:, etc) I get error messages stating various object must exist.
I think I'm close. I'm hoping somebody can figure out the correct combination of definitions to get this to work.
Thanks for any help,
UPDATE:
I believed that the error above ("Could not find the inverse association for track (:point in Track)") was being generated when attempting to save the new sky object. It is actually being generated when the new point is being added to the points collection.
At this point I have created the new sky with
sky=Sky.new( parameters)
The satellite has been created with
sat=sky.sats.build(parameters)
The track with
track=sat.build_track(empty)
Now I can do either
new_point=sat.track.points.build(parameters)
or
sat.track.points << Point.new(parameters)
to generate the inverse assoc error.
Hope this helps!
UPDATE:
Thanks to the suggestion from Eyselandic below -- here is a run-able file. It errors out on the last line with the 'inverse association' error.
# Activate the gem you are reporting the issue against.
gem 'activerecord', '6.0.0'
require 'active_record'
require 'minitest/autorun'
require 'logger'
# Ensure backward compatibility with Minitest 4
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(
adapter: 'postgresql',
database: 'database_name',
username: 'username',
password: 'password'
)
ActiveRecord::Base.logger = Logger.new(STDOUT)
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
ActiveRecord::Schema.define do
create_table "points", force: :cascade do |t|
t.bigint "track_id"
t.integer "az"
t.integer "el"
t.integer "ss"
t.boolean "used"
t.boolean "duplicate"
t.integer "PRN"
t.bigint "sky_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["PRN"], name: "index_points_on_PRN"
t.index ["created_at"], name: "index_points_on_created_at"
t.index ["sky_id"], name: "index_points_on_sky_id"
t.index ["track_id"], name: "index_points_on_track_id"
end
create_table "sats", force: :cascade do |t|
t.integer "PRN"
t.datetime "created_at", precision: 6
t.datetime "updated_at", precision: 6
t.index ["PRN"], name: "index_sats_on_PRN"
end
create_table "sats_skies", id: false, force: :cascade do |t|
t.bigint "sky_id", null: false
t.bigint "sat_id", null: false
t.index ["sat_id", "sky_id"], name: "index_sats_skies_on_sat_id_and_sky_id"
t.index ["sky_id", "sat_id"], name: "index_sats_skies_on_sky_id_and_sat_id"
end
create_table "skies", force: :cascade do |t|
t.string "klass"
t.string "tag"
t.string "device"
t.float "time"
t.float "xdop"
t.float "ydop"
t.float "vdop"
t.float "tdop"
t.float "hdop"
t.float "pdop"
t.float "gdop"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["created_at"], name: "index_skies_on_created_at"
end
create_table "tracks", force: :cascade do |t|
t.bigint "sat_id"
t.index ["sat_id"], name: "index_tracks_on_sat_id"
end
end
class Sky < ApplicationRecord
has_and_belongs_to_many :sats, inverse_of: :sky, dependent: :destroy
has_many :points, inverse_of: :sky
accepts_nested_attributes_for :sats, allow_destroy: true
accepts_nested_attributes_for :points, allow_destroy: true
end
class Sat < ApplicationRecord
has_and_belongs_to_many :skies, inverse_of: :sat, autosave: true
has_one :track, inverse_of: :sat
accepts_nested_attributes_for :skies, allow_destroy: true
accepts_nested_attributes_for :track, allow_destroy: true
end
class Track < ApplicationRecord
has_many :points, inverse_of: :track
belongs_to :sat, inverse_of: :track
accepts_nested_attributes_for :points, allow_destroy: true
end
class Point < ApplicationRecord
belongs_to :sky, inverse_of: :point #, optional: true
belongs_to :track, inverse_of: :point #, optional: true
end
class BugTest < Minitest::Test
def test_association_stuff
sky_attr= {
:klass=>"SKY",
:device=>"/dev/ttyAMA0",
:xdop=>0.62,
:ydop=>0.89,
:vdop=>0.94,
:tdop=>1.15,
:hdop=>1.23,
:gdop=>2.28,
:pdop=>1.55
}
sky = Sky.new(sky_attr)
sat = sky.sats.build(:PRN=>7)
track = sat.build_track
point_attr= {
:PRN=>7,
:el=>61,
:az=>340,
:ss=>21,
:used=>true,
# :sky_id=>nil,
:duplicate=>false
}
point=sat.track.points.build( point_attr)
sky.save
end
end
Error:
Error:
BugTest#test_association_stuff:
ActiveRecord::InverseOfAssociationNotFoundError: Could not find the inverse association for track (:point in Track)
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/reflection.rb:240:in `check_validity_of_inverse!'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/reflection.rb:474:in `check_validity!'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:43:in `initialize'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations.rb:237:in `new'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations.rb:237:in `association'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:286:in `inverse_association_for'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:107:in `set_inverse_instance'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:187:in `initialize_attributes'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:318:in `block in build_record'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/core.rb:328:in `initialize'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/inheritance.rb:70:in `new'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/inheritance.rb:70:in `new'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/reflection.rb:158:in `build_association'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:317:in `build_record'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/collection_association.rb:108:in `build'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/collection_proxy.rb:316:in `build'
active_record_gem.rb:136:in `test_association_stuff'

Related

SQLite3::SQLException: no such table

Server log screencap
Hi everyone!
Was writing a rating system for an airBnb style project so i made the objects Host and Guest as reference to the User object.
But something is wrong in my code:
SQLite3::SQLException: no such table: main.hosts
In fact the method looks for host table i dont have cause it should be associated to the Users one.
migration
class CreateReviews < ActiveRecord::Migration[6.0]
def change
create_table :reviews do |t|
t.text :comment
t.integer :star, default: 1
t.references :car, foreign_key: true
t.references :reservation, foreign_key: true
t.references :guest, foreign_key: true
t.references :host, foreign_key: true
t.string :type
t.timestamps
end
end
end
Schema
create_table "reviews", force: :cascade do |t|
t.text "comment"
t.integer "star", default: 1
t.integer "car_id"
t.integer "reservation_id"
t.integer "guest_id"
t.integer "host_id"
t.string "type"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["car_id"], name: "index_reviews_on_car_id"
t.index ["guest_id"], name: "index_reviews_on_guest_id"
t.index ["host_id"], name: "index_reviews_on_host_id"
t.index ["reservation_id"], name: "index_reviews_on_reservation_id"
Models:
class HostReview < Review
belongs_to :host, class_name: "User"
end
class User < ApplicationRecord
....
has_many :host_reviews, class_name: "HostReview", foreign_key: "host_id"
I think you can do something like this:
t.references :host, references: :users, foreign_key: true
or alternatively
t.integer :host_id
and then
add_foreign_key :reviews, :users, column: :host_id

Creating a modal instance on the attribute update of another in Rails?

I'm building a Rails app that has modals Outage, Service, Note and User.
Service has a boolean attribute is_down. By default, is_down is false. When the attribute is updated to true meaning the service goes down, an Outage should be created and a Note should also be created with User, automated.
This all happens in one update of the is_down attribute. If Service goes back up, the outage remains intact but now has an end_time.
Here is the 'story line`:
Service model:
class Service < ApplicationRecord
has_many :outages
has_many :notes
# This is where I'm confused
is_down
if self.is_down
Outage.create(start_time: Time.now, reason: nil)
Note.create(user_id: 1, entry: "Outage began at #{Time.now}", service_id: self.id)
end
end
end
Outage model:
class Outage < ApplicationRecord
belongs_to :service
has_many :notes
has_many :users, through: :notes
end
Note modal (a join table between Outage and User)
class Note < ApplicationRecord
belongs_to :outage
belongs_to :user
end
and User model:
class User < ApplicationRecord
has_many :notes
has_many :outages, through: :notes
end
Outage is more like a story line where during the outage, users can enter notes about what they've learned.
Here is the schema:
enable_extension "plpgsql"
create_table "notes", force: :cascade do |t|
t.text "entry"
t.boolean "is_public", default: true
t.bigint "outage_id"
t.bigint "user_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["outage_id"], name: "index_notes_on_outage_id"
t.index ["user_id"], name: "index_notes_on_user_id"
end
create_table "outages", force: :cascade do |t|
t.datetime "start_time"
t.datetime "end_time"
t.text "reason"
t.boolean "is_recurring", default: false
t.string "frequency", default: "None"
t.bigint "service_id"
t.index ["service_id"], name: "index_outages_on_service_id"
end
create_table "services", force: :cascade do |t|
t.string "name"
t.boolean "is_down", default: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "users", force: :cascade do |t|
t.string "username"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
add_foreign_key "notes", "outages"
add_foreign_key "notes", "users"
add_foreign_key "outages", "services"
end
Besides the initial question of automated creation on update of Service attribute, is_down, is this also a good way to go about implementing this?
I would suggest looking into the lifecycle callbacks for ActiveRecord. You can add an after_save callback to your Service class that checks to see if is_down has changed and then create or close an Outage
class Service < ApplicationRecord
has_many :outages
...
after_save :create_or_update_outage, if: is_down_changed?
...
private
def create_or_update_outage
if is_down
outages.create
else
outages.where(end_time: nil).last.update(end_time: Time.now)
end
end

unknown attribute with polymorphic association

In my online shop I have tables Product and Size, also I think I need to add a table Restocking
Instead of updating a product, I guess It's better to have a Restocking table then I could track the dates where I added any new sizes, quantity, and why not the new prices (buying and selling)... and create stats...
Do you this it is correct?
Once a Restocking is created, the corresponding Product is updated with new quantity and price?
Well,
So it started this way:
#Product
has_many :sizes
accepts_nested_attributes_for :sizes, reject_if: :all_blank, allow_destroy: true
#Size
belongs_to :product
The Restocking table needs to have sizes attributes (like product)
I believe that I have to use polymorphic associations, but how I am supposed to update my schema , what should I add, remove?
So since I added the Restocking model, my models look like this:
#Product
has_many :sizes, inverse_of: :product, dependent: :destroy, as: :sizeable
has_many :restockings
accepts_nested_attributes_for :sizes, reject_if: :all_blank, allow_destroy: true
#Restocking
has_many :sizes, as: :sizeable
belongs_to :product
accepts_nested_attributes_for :sizes, reject_if: :all_blank, allow_destroy: true
#Size
belongs_to :product
belongs_to :restocking
belongs_to :sizeable, polymorphic: true, class_name: "Size"
schema.rb
create_table "sizes", force: :cascade do |t|
t.string "size_name"
t.integer "quantity"
t.bigint "product_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "quantity_stock"
t.index ["product_id"], name: "index_sizes_on_product_id"
end
create_table "restockings", force: :cascade do |t|
t.bigint "product_id"
t.bigint "sizeable_id"
t.decimal "price", precision: 10, scale: 2
t.decimal "buying_price", precision: 10, scale: 2
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["product_id"], name: "index_restockings_on_product_id"
t.index ["sizeable_id"], name: "index_restockings_on_sizeable_id"
end
create_table "products", force: :cascade do |t|
t.string "title", limit: 150, null: false
t.text "description"
t.bigint "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "color"
t.integer "user_id"
t.json "attachments"
t.string "brand"
t.string "ref"
t.decimal "price"
t.decimal "buying_price", precision: 10, scale: 2
t.index ["category_id"], name: "index_products_on_category_id"
end
At this point I have several errors, like
in ProductsController
def new
#product = Product.new
#product.sizes.build
end
error:
ActiveModel::UnknownAttributeError at /admin/products/new
unknown attribute 'sizeable_id' for Size.
Can you light me on the migrations I have to change?
Suggestions are welcome
You're almost there, to use polymorphic inside your Size model, you have to change the size resource, and add two attributes to the resource: sizeable_id and sizeable_type.
The sizeable_type is a string, indicates the class of the parent element, in your case, can be Product or Restocking, and sizeable_id indicates the element_id to find the parent element, your relations are correct, but you must add this elements to your Size, see the following:
One exemple of a migration to your case:
class AddSizeableToSize < ActiveRecord::Migration
def change
add_reference :sizes, :sizeable, polymorphic: true, index: true
end
end
On your Size model:
# app/models/size.rb
class Size < ActiveRecord::Base
belongs_to :sizeable, polymorphic: true
end
In your Product or Restocking model:
has_many :sizes, as: :sizeable
This is just a simple way to make your case works! If you want to know more about rails associations and polymorphism, can take a look in this link.

association is not connected (rails)

I want to display %h4 #{message.user_id.name} with association of message model & user model
I'm getting an error:
Showing /Users/ryousuke/projects/chat-space/app/views/messages/_message.html.haml
undefined method `name' for 3707:Fixnum
Trace of template inclusion: app/views/messages/index.html.haml
I've tried...
to check the association:
class Message < ApplicationRecord
belongs_to :user
belongs_to :group
end
class User < ApplicationRecord
 has_many :messages
has_many :group_users
has_many :groups, through: :group_users
end
to check foreign_key:
create_table "messages", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "content", `enter code here`limit: 65535, null: false
t.string "image"
t.integer "user_id", null: false
t.integer "group_id", null: false
t.index ["group_id"], name: "fk_rails_841b0ae6ac", using: :btree
t.index ["user_id"], name: "fk_rails_273a25a7a6", using: :btree
to check data existence usertable id:3707
user_id returns the ID - a number. What you want is just user, which will return the actual user object.
%h4 #{message.user.name}

Ruby on Rails 4.2, stack level too deep, associations and delegate()

I understand the cause of a Stack Level Too Deep error. I am failing to spot where/why it is occurring in my code base.
I've implemented a multi-model, multi-step wizard. The first two models (User and Company) are working, it is when I attempt to add in the third (Address) I get the error.
I suspect the error is related to the associations between the models, although I've failed to debug.
The code snippets below function correctly except when I add the 3 lines (marked with comments in the snippet) too the file app/wizards/user_wizard/step1.rb.
Relevant Models
app/models/company.rb
class Company < ActiveRecord::Base
include Validatable::Company
# Associations:
has_many :addresses, inverse_of: :company
accepts_nested_attributes_for :addresses, reject_if: :all_blank
has_many :employees, inverse_of: :company
accepts_nested_attributes_for :employees, reject_if: :all_blank
has_many :licenses, inverse_of: :company
accepts_nested_attributes_for :licenses, reject_if: :all_blank
has_many :vehicles, inverse_of: :company
accepts_nested_attributes_for :vehicles, reject_if: :all_blank
has_one :user, inverse_of: :company
end
app/models/address.rb
class Address < ActiveRecord::Base
# Associations:
belongs_to :company, inverse_of: :addresses
has_many :licenses, inverse_of: :address
accepts_nested_attributes_for :licenses, reject_if: :all_blank
has_many :initial_analyses, inverse_of: :address
accepts_nested_attributes_for :initial_analyses, reject_if: :all_blank
end
app/models/user.rb
class User < ActiveRecord::Base
include SoftDeletable
include Validatable::User
# Constants:
MARKER_ATTRIBUTES = %w[user_name].freeze # get marked with '(deleted)'
DEPENDANT_CHILDREN = %w[none].freeze # child resources to be deleted
# Associations:
belongs_to :role, inverse_of: :users
belongs_to :company, inverse_of: :user
accepts_nested_attributes_for :company, reject_if: :all_blank
has_many :auto_quotes, inverse_of: :user
end
db/schema.rb
ActiveRecord::Schema.define(version: 20170616131833) do
create_table "addresses", force: :cascade do |t|
t.integer "company_id"
t.text "site_name"
t.string "premises_code"
t.string "exempt_premises_code"
t.text "address"
t.string "city"
t.string "county"
t.string "sic_code"
t.string "postcode"
t.string "country"
t.boolean "sic_update"
t.boolean "deleted", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
end
create_table "companies", force: :cascade do |t|
t.string "company_name"
t.string "registration_number"
t.string "type_of_business"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "failed_attempts", default: 0, null: false
t.string "unlock_token"
t.datetime "locked_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "user_name"
t.datetime "deleted_at"
t.integer "role_id"
t.integer "company_id"
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.integer "invited_by_id"
t.string "invited_by_type"
t.integer "invitations_count", default: 0
end
add_index "users", ["company_id"], name: "index_users_on_company_id", unique: true
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true
add_index "users", ["invitations_count"], name: "index_users_on_invitations_count"
add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id"
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
add_index "users", ["unlock_token"], name: "index_users_on_unlock_token", unique: true
end
Wizards
app/wizards/user_wizard/base.rb
module UserWizard
class Base
include ActiveModel::Model
STEPS = %w[step1 step2].freeze
attr_accessor :user
delegate(*::User.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :user)
def initialize(user_attributes)
#user = ::User.new(user_attributes)
end
end
end
app/wizards/user_wizard/step1.rb
module UserWizard
class Step1 < UserWizard::Base
include Validatable::Company
attr_accessor :company
# One of 3 lines triggering circular reference by adding in Address model
attr_accessor :address
delegate(*::Company.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company)
# One of 3 lines triggering circular reference by adding in Address model
delegate(*::Address.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :address)
def initialize(user_attributes)
super
#company = #user.build_company
# One of 3 lines triggering circular reference by adding in Address model
#address = #user.company.addresses.build
end
end
end
app/wizards/user_wizard/step2.rb
ommitted as it is irrelevant. code fails before ever instantiating this class
address has an address attribute. So the delegate method is trying to create a method address that will be delegated to address.
I'd suggest this:
module UserWizard
class Step1 < UserWizard::Base
include Validatable::Company
attr_accessor :company
# One of 3 lines triggering circular reference by adding in Address model
attr_accessor :company_address
delegate(*::Company.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company)
# One of 3 lines triggering circular reference by adding in Address model
delegate(*::Address.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company_address)
def initialize(user_attributes)
super
#company = #user.build_company
# One of 3 lines triggering circular reference by adding in Address model
#company_address = #user.company.addresses.build
end
end
end

Resources