Rails 5 belongs_to_required_by_default doesn't work - ruby-on-rails

I use Rails 5.0.0, but for some reason belongs_to_required_by_default doesn't work!
Application was created as new rails 5 app
class Visit < ApplicationRecord
belongs_to :user
end
> v = Visit.new
> v.valid? # => true
it works only with optional: false option
class Visit < ApplicationRecord
belongs_to :user, optional: false
end
> v = Visit.new
> v.valid? # => false
but why doesn't work configuration:
Rails.application.config.active_record.belongs_to_required_by_default = true

Where are you putting it? Have confirmed it works by putting it in development.rb as config.active_record.belongs_to_required_by_default = true inside Rails.application.configure do.
If you want it for everything you can put it in application.rb under class Application < Rails::Application as config.active_record.belongs_to_required_by_default = true
I believe you'll find putting it in the initializers directory will have problems with the loading order.

EDIT FOR RAILS 5.1: Everything should work well on a default Rails 5.1 application. Just make sure config.load_defaults 5.1 is in your application.rb (reference).
OLD ANSWER FOR RAILS 5.0.x
It look like this is due to some gems that monkey patch activerecord incorrectly, according to this Rails issue https://github.com/rails/rails/issues/23589.
You may want to comment/uncomment them out in your Gemfile until you find the culprit.
After this tedious process, I found that for my latest project it was the gems ahoy_matey, cancancan and delayed_job_active_record that caused the problem (at the time of writing).
In the meantime Ropeney's answer works, although not ideal since the "official rails way" is to declare config.active_record.belongs_to_required_by_default = true in the new_framework_default‌​s.rb initializer, not in application.rb.

In case anyone is still having this issue, you can upgrade to Rails 5.1 to fix it. In Rails 5.1, config/initializers/new_framework_defaults.rbhas been removed and replaced with the line config.load_defaults 5.1 in application.rb. This line includes
active_record.belongs_to_required_by_default = true and the other options that were in new_framework_defaults.rb.
module myApp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails
version.
config.load_defaults 5.1
See the end of this thread for more details: https://github.com/rails/rails/issues/23589.

active_record.belongs_to_required_by_default = true only works for FactoryBot.create() method. you will still get validation error of child records not present where you have used FactoryBot.build() method. Any idea why this is not working for build()? any workaround?

Related

Rails 6.1 development environment not printing query trigger code line with verbose active

I have both lines:
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
ActiveRecord::Base.verbose_query_logs = true
in my config/environments/development/rb
But in my development log the sql queries are logged like:
2022-08-10 08:35:18.536410 D [74:puma srv tp 004] (0.006ms) ActiveRecord -- Model Load -- { :sql => "SELECT ....", :binds => { .... }, :allocations => 1, :cached => true }
I have an N+1 queries issue to fix, but the information about which line in the code triggered the query is missing, so this is not helping me much.
I tried also using active-record-query-trace gem, with configuration:
if Rails.env.development?
ActiveRecordQueryTrace.enabled = true
ActiveRecordQueryTrace.level = :full
ActiveRecordQueryTrace.colorize = true # No colorization (default)
ActiveRecordQueryTrace.colorize = :light_purple
# Optional: other gem config options go here
end
but I see no changes at all in how queries are logged.
How can I enable the logging of the line triggering the query?
Thanks
If you want to know the reference point that made a DB query I used to use a gem called Marginalia. I use it in Rails 6 and it does exactaly what you are looking for.
From what I am reading Rails 7 includes this feature as a native feature (which is quite awesome I might add).
I found a link that talks about this:
Rails 7 includes Marginalia
Their example says:
# config/application.rb
module Saeloun
class Application < Rails::Application
config.active_record.query_log_tags_enabled = true
end
end

Zeitwerk doesn't requires lib classes properly in Rails 6.1.6

I'm trying to update my app from Rails 5.2 to 6.1, and use Zeitwerk autoload, and I am having some issues for autoloading /lib classes.
I included this in config/application.rb:
config.load_defaults 5.2
config.autoloader = :zeitwerk
config.enable_dependency_loading = true
config.autoload_paths += Dir[Rails.root.join('lib/**/*')]
config.eager_load_paths += Dir[Rails.root.join('lib/**/*')]
And, when I run zeitwerk:check, it alerts me that:
Hold on, I am eager loading the application.
expected file lib/facades/coconut/v2/foo.rb to define constant Foo
It is declared as:
# /lib/facades/coconut/v2/foo.rb
module Coconut
module V2
class Foo
# ...
end
end
end
When I try to debug it (putting a binding.pry in some test file), Zeitwerk says it do not defined, until I call it without modules (namespaces):
[1] pry(#<#filename>)> Coconut::V2::Foo
NameError: uninitialized constant Coconut::V2::Foo
from (pry):1:in `setup`
[2] pry(#<#filename>)> Foo
Zeitwerk::NameError: expected file /my-app/lib/api/coconut/v2/foo.rb to define constant Foo, but didn't
from /usr/local/bundle/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/callbacks.rb:25:in `on_file_autoloaded'
[3] pry(#<#filename>)> Coconut::V2::Foo
=> Coconut::V2::Foo
It sounds really strange, because there are another classes in /lib that follows the same structure, but it works well, example
# /lib/api/services/youtube/client.rb
module Services
module Youtube
class Client
# ...
end
end
end
Inspecting it with binding.pry in some test:
pry(#<#filename>)> Services::Youtube::Client
=> Services::Youtube::Client
Has anyone had this problem or know what could be happening?
System:
ruby 2.7.6p219
Rails 6.1.6
Zeitwerk (2.5.4)
An autoload path is a root directory, not its contents.
You need to remove the wildcards as documented here.

"Unable to autoload constant User" error when changed code in development

I have a problem with my rails application. After an Update from Rails 3 to 4.
When I surf through the pages after starting the server in development mode everything is fine.
But after a single code change (even adding a space) every page request shows the following error.
Unable to autoload constant User, expected
/path/to/my/rails-app/app/models/user.rb to define it
The file lives exactly there and defines the class:
class User < ActiveRecord::Base
…
I tried many things with config.autoload_paths and config.eager_load_paths in application.rb but with no luck.
Deactivating spring did not help either.
Developing an app and having to restart the server after every single change seems so 90s.
$ rails -v
Rails 4.2.4
$ ruby -v
ruby 2.1.7p400 (2015-08-18 revision 51632) [x86_64-linux]
Some relevant configs:
development.rb
MyApp::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the webserver when you make code changes.
config.cache_classes = false
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
# Do not compress assets
config.assets.compress = false
# Expands the lines which load the assets
config.assets.debug = true
config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = {
host: 'localhost',
port: 3000
}
end
application.rb
module Serviceportal
class Application < Rails::Application
# Enable the asset pipeline
config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
[… some asset precompile stuff …]
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = 'utf-8'
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir["#{config.root}/app/mailers",
"#{config.root}/app/controllers/concerns",
"#{config.root}/app/models/concerns",
"#{config.root}/app/decorators/concerns",
"#{config.root}/lib",
"#{config.root}/lib/shared"
]
config.eager_load_paths += Dir["#{config.root}/app/mailers",
"#{config.root}/app/controllers/concerns",
"#{config.root}/app/models/concerns",
"#{config.root}/app/decorators/concerns",
"#{config.root}/lib",
"#{config.root}/lib/shared"]
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
config.time_zone = 'Berlin'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
config.i18n.default_locale = :de
[… some SQL and active support stuff …]
config.action_controller.include_all_helpers = false
config.action_controller.action_on_unpermitted_parameters = :raise
# Do not swallow errors in after_commit/after_rollback callbacks.
config.active_record.raise_in_transactional_callbacks = true
end
end
Edit: The error mostly shows up in lib/auth/user_proxy.rb in the following function. Maybe this helps to narrow the range of possible causes.
def self.usertype_allowed?(type)
[ User, TempCustomer ].include? type.classify.safe_constantize rescue false
end
Edit 2: Stringify the class names in Edit 1 helped (thanks #Benjamin Sinclaire). But only leads to the next errors. I could also avoid using classes. But at the following error in app/controllers/concerns/security.rb there is nothing can change?
Unable to autoload constant User, expected
/path/to/my/rails-app/app/models/user.rb to define it
code:
def set_current_user
User.current = current_user
end
with current user saved in the Thread (code from /path/to/my/rails-app/app/models/user.rb
def self.current
Thread.current['current_user']
end
def self.current=(user)
Thread.current['current_user'] = user
end
Just to make it clear again: It works after server restart in development until I change some code somewhere.
1 See if you have any multiple-level class or module declaration done one one line and change them to be declared in several lines.
Instead of
class Parent::Sub::Child
end
Do
module Parent
module Sub
class Child
end
end
end
2 Check your model association definitions, and ensure you are never using constant. Use string instead.
Instead of
belongs_to :manager, class_name: User
Do
belongs_to :manager, class_name: 'User'
3 Just saw your edit. Can you refactor like this?
# I assume `type` is a string or such, so we can compare classes
# names instead of constants, and get rid of `safe_constantize`
def self.usertype_allowed?(type)
['User', 'TempCustomer'].include? type.classify rescue false
end
4 Not a good idea to serialize an active record object in the Thread storage. Change it to store the user id instead, like this:
def set_current_user
User.current = current_user.id
end
def self.current
Thread.current['current_user_id']
end
def self.current=(user_id)
Thread.current['current_user_id'] = user_id
end
You don't need include app/models/concerns and app/controllers/concerns in your autoload/ eagerload paths as they are included by default in Rails 4: https://signalvnoise.com/posts/3372-put-chubby-models-on-a-diet-with-concerns
Also make sure that your concerns are defined as modules, extend ActiveSupport::Concern and with the appropriate file name
#taggable.rb
module Taggable
extend ActiveSupport::Concern
end
Another cause of your problem might be that some modules/ classes in app/decorators/concerns, lib, lib/shared are using the User class
which is not loaded yet or some of it's dependencies are not loaded so try adding require_relative path_to_user.rb at the top of those files
-----Edit-------
Try adding at the top of lib/auth/user_proxy.rb
require_dependency 'app/models/user'
This way you'll remove any ambiguity in autoloading the User class and you won't mess around with Rails autoloading see more here: http://guides.rubyonrails.org/autoloading_and_reloading_constants.html#require-dependency , http://guides.rubyonrails.org/autoloading_and_reloading_constants.html#common-gotchas
Same problem but in an engine w/ namespaces. No issues in production or in development until a code-change / autoload.
The solution was to
checking for double definitions (there were none)
checking if the module nesting strictly follows rails conventions in the filesystem.
I've had myns under myengine/app/myns/subns/obj.rb but myns is being ignored as it is at the root of the app folder, so moving the myns folder into a subfolder myengine/app/lib/myns solved the issue.
Note: the rails error message was very explicit about the module nesting (while still pointing to the wrong .rb file in the filesystem) so look closely at the error. The error was 'Unable to autoload constant subns/obj.rb in .../myns/subns/obj.rb'. Rails suggesting the incorrect file-location (which exists) is misleading in this case.
During a Rails/Ruby Update I found time to look into this and finally found the cause.
The user class had an unloadable in it for years. That caused the problems since Rails 4. Now I removed this and found no issues after that.

ActiveSupport encode_big_decimal_as_string

I would like to use the ActiveSupport option encode_big_decimal_as_string on one of my models. Should I put it in the model? Do I call this method on a model instance? Do I place this somewhere in config? What is an ActiveSupport option and how could I use it?
Neither of these answers worked for me in Rails 4.0. Here is what works in Rails 4.0:
ActiveSupport::JSON::Encoding.encode_big_decimal_as_string = false
Add that line to your application config, like so:
# config/application.rb
...
module AppName
class Application < Rails::Application
...
ActiveSupport::JSON::Encoding.encode_big_decimal_as_string = false
...
end
end
As #tyler-nguyen said, this is being deprecated in Rails 4.1, and extracted into this gem: ActiveSupport JSON Encoder. Refer to the gem documentation for configuration in 4.1.
In Rails 4.0, you can set it in your application.rb as following:
config.active_support.encode_big_decimal_as_string = false
From Rails 4.1, the ActiveSupport.encode_big_decimal_as_string option is deprecated. The feature has been extracted to the activesupport-json_encoder gem.
I believe that you do it in the environment.rb file.
This is what should work. I don't have a way to test it right now.
Rails::Initializer.run do |config|
config.active_support.json.encode_big_decimal_as_string = true
end

Rails 2.3.2 and SHOW TABLES

I have annoying problem with SHOW TABLES in my Rails 2.3.2 APP - it is slowing my APP very deep. The question is, how to get rid of SHOW TABLES usage and where it is used in Rails framework? From APP logs I can see that it is being used all the time.
Thank you!
config/environments/production.rb:
config.cache_classes = true
config.action_controller.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
"SHOW TABLES" is ORM-dependent SQL query, it fires with every action to provide classes reload in development mode. How much time does the query take?
I was seeing a similar problem in Rails 3.0 and was able to fix it using the gist pointed to from this issue. Looks like it's fixed in Rails 3.2.
I added ar_patch.rb to config/initializers with this code:
unless Rails.env.development?
require "active_record/connection_adapters/mysql2_adapter"
module ActiveRecord
module ConnectionAdapters
class Mysql2Adapter < AbstractAdapter
extend ActiveSupport::Memoizable
memoize :tables, :pk_and_sequence_for, :columns
end
end
end
end

Resources