stack level too deep (when changing model inheritance) - ruby-on-rails

I'm trying to use the citier gem to convert some models that already exist in the following way. So far this works:
Created models:
Attachable < ActiveRecord::Base
Link < Attachable
I added acts_as_citier to both models, created and ran the migrations with no problem. Database views are created as well. Now if I try to do this to an existing model:
Before:
SpecialLink < ActiveRecord::Base
After:
SpecialLink < Link
and then I try to run any command like rails g migration or rails console, I get:
script/rails:6: stack level too deep (SystemStackError)
Unfortunately, this doesn't tell me a whole lot beyond a suspicion that I have an infinite loop somewhere. Does anyone know what might be causing this? Or have an idea of where I can look or get more information about the issue? It would not be a good solution for me to have to create the models again from scratch to work with citier...

Related

Rails 6 app not validating belongs_to associations

I have a rails engine which encapsulates a piece of my application's funtionality. I have a bunch of models in the engine, which have various belongs_to associations defined. As of rails 5 these associations are supposed to be required by default, unless optional: true is specified in the definition.
I’m still able to create instances of the models without any validation errors. I haven’t specified optional: true on any of the associations, nor is the config optionconfig.active_record.belongs_to_required_by_default set anywhere. Besides, it was removed in rails 6 anyway.
I can't think of any reason the model instances would not fail validation. I would expect any instances of any model with an undefined belongs_to association would be invalid and raise an error. Why would these records pass validation?
I found my problem, thanks to #MatthiasWinkelmann for the tip. It turns out my engine was not calling load_defaults at all. I needed to add the following to spec/dummy/config/application.rb:
module Dummy
class Application < Rails::Application
config.load_defaults Rails::VERSION::STRING.to_f
... etc ....
end
end
here is an article containing more explanation:
An upgraded Rails gem does not upgrade your Rails configuration
I probably would have done better to mention in my question that I'm in the process of upgrading my application from Rails 4.2 to 6.1. The change was introduced in Rails 5.

ruby require relative quesiton

Hello I am trying to learn how to make a ruby on rails app. I am stuck on the require_relative syntax. Currently I have a game_runner.rb file, that is not in the app directory, that is supposed to get a method (who_is_hider) from role.rb that is in models. Am I typing it correctly? When I run the current code I get an "uninitialized constant ApplicationRecord" error. This makes no sense since I have a application_record.rb file that has (self.abstract_class = true) inside. Thank you for your time.
game_runner.rb
require_relative './app/models/Role'
who_is_hider
role.rb
class Role < ApplicationRecord
belongs_to :round
belongs_to :player
enum label: {seeker: 1, hider: 2, decoy: 3}
validates :player_id, uniqueness: {scope: :round_id}
def who_is_hider
p "made it here"
end
end
application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
I am stuck on the require_relative syntax. […] Am I typing it correctly? When I run the current code I get an "uninitialized constant ApplicationRecord" error.
Yes, your syntax is correct. If your syntax were incorrect, your code wouldn't even run in the first place, and you would get a SyntaxError. The fact that your code does run and produce a NameError exception shows without a doubt that your syntax is correct.
As an easy way to check whether your syntax is correct, you can
visually inspect the syntax coloring in your editor,
visually inspect the syntax coloring in the Stack Overflow question, if you post one,
run ruby -c to check the syntax
The last one is the preferred option if you have it available, of course. But sometimes, you are writing code in an environment where you don't have a Ruby execution engine available, and in that case, you can at least use your editor or even the (admittedly not very good and easily confused) highlighting that Stack Overflow uses. While especially the latter one is not very good, it still does tend to highlight easy mistakes caused by typos, e.g. unterminated string literals.
Hmmm, you are using a single ruby file and expecting to load all rails environment? your Role model knows about ApplicationRecord because Rails loads a LOT of things on the background. If Rails is not in the middle then you have to explicitlly tell what thinks to load. You can require ApplicationRecord on the game_runner file or inside role.rb, but then you'll have to require ActiveRecord too.
I don't think it's a good idea to do what you are trying to do. If you wan't to run some script that depends on your environment, I'd recommend you to use a rake task, it will handle the loading of the environment. If you still want to make your game_runner.rb run as is, then you'll have to import everything the interpreter complains about until it works.

Rails Engine: Create dummy model for relations?

I am trying to make a Rails Engine that can be plugged into my applications and manage friendships between users. To do that, all the logic dealing with friend requests, acceptance, etc, is going to live in a Rails Engine.
When I create my Friendship model, it needs a belongs_to relation for two Users (two friends). But, I don't want to tie a user to this engine. I want this engine to work generically with any User an application has established.
What technique does one use to create a dummy User that is never to be included in the host application? (I want to avoid a migration of the engine pulling in this dummy User.)
Update:
I removed the second question, pertaining to how to then override the engine's User with the host app's User. I found the answer to that in the guides (http://edgeguides.rubyonrails.org/engines.html#configuring-an-engine).
tl;dr
cd into engine's dummy app root
run rails g model User
run rake db:migrate
Discussion
I came here looking for an answer, but seeing how there were no answers, I will share how I ended up solving this.
When creating a mountable Rails engine (via something like rails plugin new . --mountable --dummy-path=spec/dummy), Rails will generate a "dummy" app for your engine that will serve as the main app an engine would normally be required into.
Us RSpec users use the "--dummy-path" directive and put the dummy app in /spec folder, but for you it may be elsewhere. Find where it is and cd into that dummy app's root.
Once inside the dummy app, call rails g model User to generate a User model for the dummy app. Run rake db:migrate to add the table.
Now you have a placeholder User model that should function acceptably in tests as an association.
You may want to define some mock methods on User, do so in the model definition file located in /path/to/dummy/app/models/user.rb
Naturally, you can make a full-fledged model with associations and logic instead of just a placeholder right there in dummy.
Migrations and code in dummy app are not used when an engine is included in an app,as rake railties:install:migrations will show.
This might be a bit hacky!
I have an app with several engines. Each engine needs to call a limited amount of functionality in the other engines.
For example, Engine1 and Engine2 don't depend on (require or load) each other. However, a model such as Engine1::User might need to call a selection of records using a scope called all_active from the Engine2::Department model. That's okay inside the context of the overall Rails app into which both engines are loaded as Gems.
The problem arises for the developer of Engine1 when they want Engine2::Department.all_active, and they don't have it.
The solution I am using is to create a "mocked model" (for want of a better phrase) in Engine2's test/dummy/app/models (or spec/dummy/app/models if you're using RSpec) folder.
Something like this will work in Engine1:
# spec/dummy/app/models/engine2/department.rb
require '../../app/models/engine2/department' if File.exist?('../../app/models/engine2/department')
module Engine2
class Department
unless Engine2::Department < ActiveRecord::Base
def self.all_active
[{ id: 1, name: 'Finance', active: true},
{ id: 2, name: 'Sales', active: true}]
end
end
end
end
Because this file is in the dummy app, it won't get found by the main Rails app, so it won't interfere there. It will only get loaded in the dummy rails app during development and testing.
FYI, the unless Engine2::Department < AR::Base detects if the Department model inherits from ActiveRecord already, and if it does, the enclosing code won't be loaded. This is a safety mechanism to prevent the class method all_active from being overwritten by the hard-coded sample data in the hash shown above.
If you have a lot of engines in your system, perhaps you should consider creating a git repo of an engine template that can be pulled into each engine (containing common code, etc).
Your sample data might benefit from being OpenStruct objects, so your hash keys can be accessed using dot notation. You could then write code such as #engine2_departments.first.name rather than #engine2_departments.first[:name].

Rails "superclass mismatch for class (TypeError)". A well documented error, but I need some tailored advice

Ok. I understand why I'm getting this error. According to another StackOverflow question, "That error shows up when you redeclare a class that’s already been declared". This question seems to point out the solutions, but not quite. I have some additional questions.
Here's what I have...
/models/item.rb
class Item < ActiveRecord::Base
..
end
class Theme < Item
end
class Setting < Item
end
This Item model has existed for quite some time. I recently added the sing inheritance for Theme and Setting.
As well as...
/models/setting.rb
class Setting < ActiveRecord::Base
..
end
/models/theme.rb
class Theme < ActiveRecord::Base
..
end
So it makes sense why I'm getting the error. I never got the error in my local workspace, only when I pushed everything to heroku, did my migrations, and then tried to run "heroku run rails c". As soon as I run that command, I get the error and immediately get booted out.
According to some answers, I should quit console and come back in. However, I can't get in to begin with. As soon as I launch "heroku run rails c", I get booted.
Additionally, if I completely wipe my DB, and remigrate everything, am I going to get the same error given the order of operations of these table creates, etc? I don't want to have to hack a solution to fix it everytime. If I run all my migrations, ideally everything would be working straight away.
What do I do to solve this issue?
You're trying to redefine the Theme and the Setting model. In your app/models/item.rb you define them as inherited from Item class and in the app/models/theme.rb and app/models/setting.rb you define them to inherit from ActiveRecord::Base directly.
You can see this error only in the heroku (probably production) environment because in dev env the eager loding option is turned off by default and therefore Rails does not load in all the classess when it boots.
Is your Item model using single table inheritance (STI)? Because that is the only case when you need to inherit the Theme and Settings model from your Item model.
If it is move your Theme and Setting class definitions to the app/models/theme.rb and app/models/setting.rb files accordingly and remove the definitions from there.
If not, then simply remove the Theme and Setting class definitions from the app/models/item.rb file and you'll be good to go.

Rails remove old models with migrations

I have a bunch of rails models that I'm re-writing into a single model to simplify my code and reduce unnecessary tables.
I'm wondering what the best way to delete a model class and its table is. I want past migrations to still succeed, but I don't want to leave the empty models lying around.
Do I have to manually delete the old migrations that reference these models, then manually delete the class files?
Does anyone have any tips for the best way to do this?
All in one solution.
Run the following commands:
rails destroy model ModelName
rails g migration DropTableModelName
The former will generate a new migration file which should looks like this:
class DropTableModelName < ActiveRecord::Migration
def change
drop_table :model_name
end
end
Now run db:migrate and you're done.
If you'd like to completely get rid of of a model and its table do this:
rails destroy model Name
The question is a bit stale now, but I just did:
rails destroy scaffold <ModelName> -p
The -p flag shows "pretend" output, which is good for seeing what will happen. Remove the '-p' flag and the results will match the output. This cleaned the entire collection of M-V-C files + testing + js files + the original migration, no problem.
I guess if you are one who likes to hand edit your migrations and include multiple steps in each, losing the original migration could break db:setup, so buyer beware. Keeping one action == one migration file should avoid this potential snafu.
What about doing ruby script/destroy model? That should take care of the model and the migration.
Depending on how far into development or production you are, you may want to migrate the models out safely using a migration to remove/backup data or what not. Then as bobbywilson0 suggested, using
script/destroy model
or if you rspec anything
script/destroy rspec_model
This will remove any spec tests as well.
Or you can always just drag them to the trash folder.
You can take a look at this one at rails guide.
But I suggest, if it is possible, you should delete the models and all references to the models. This will probably save time later as you don't need to maintain the dead code in the codebase.
If you'd rather have a manual based answer:
First run the following command to identify which migrations you want removed:
rake db:migrate:status
Feel free to grep -i on it too if you're confident of your naming scheme.
Make note of all the "add x to model name" and similar alterations to your Model. These can be removed using:
rails d migration AddXToModelName
Do this for every migration besides the initial create migration. The following command will take care of the initial create migration and the files associated with the model:
rails d model ModelName

Resources