Rails 3 - uninitialized constant Setting::Paymentshop - ruby-on-rails-3

I am getting still this error, Setting and Paymentshop are models.
class Setting < ActiveRecord::Base
has_many :paymentshops
end
class PaymentShop < ActiveRecord::Base
belongs_to :setting
end
In view I have problem on this line:
dopr.paymentshops.type_v
dopr is variable with data from Setting and type_v is column in table Paymentshops.
I would like to ask you, If could anyone help me please with this error...
Thanks

Rails tries to automatically infer the model name from the relation name. With no indication of where to break the single lower-case stream of characters, it assumes that the target model is called Paymentshops.
You can explicitly override the expected class name with has_many :paymentshops, :class_name => "PaymentShop". Alternatively, you could try using has_many :payment_shops - I'm not 100% sure how Rails modifies the relation names, but I think that should map to PaymentShop directly.

Related

uninitialized constant in rails?

So I've built a new controller = "Categories_controller.rb" and a new Model = "Category.rb" and now I would normally take my Savedfriend.rb model and use it with Category.rb model like so;
<%= category.savedfriends.size %>
However this time around I keep getting;
uninitialized constant Category::Savedfriend
It's driving me crazy. I do have models all set with belongs_to.
By Rails convention, if you haven't specified your class_name on the association, it is going to look for a singularized, camelized version of the association name for the class name. If, for instance, you have a model SavedFriend, your association should be named saved_friends. If it can't find the class for the association, Rails tends to look for a scoped class within the class that's trying to call it. The error is a little obscure, but I've seen it plenty of times when I have a typo in my associations.
# in app/models/saved_friends.rb
class SavedFriend < ActiveRecord::Base
belongs_to :category
end
# in app/models/category.rb
class Category < ActiveRecord::Base
has_many :saved_friends
end
Also, if your naming scheme for files and classes is as sporadic as it is in your question, you're going to have a bad time. File names should be lowercase and underscored, class names should be a camelized version of the file name. i.e. Categories_controller.rb should be categories_controller.rb, and the class should be CategoriesController. Similarly, saved_friend.rb should contain class SavedFriend.

has_many association ignores restricting condition

I'm working on a Rails 3.0.x application (actually it's Hobo 1.3.x but that's not material to this question). Among the models, there are GraphPanes, GraphLabels, and LabelSets. A GraphPane can have GraphLabels and LabelSets. GraphLabels can belong to GraphPanes or LabelSets, but not both. So if a GraphLabel belongs to a LabelSet, I'd like to keep it from being associated to a GraphPane.
I am trying to enforce that with this code in the GraphPane model:
has_many :graph_labels, :conditions => 'label_set_id = NULL'
However, I'm still able to associate GraphLabels with not-null label_set_id with GraphPanes. Why? How can I stop this?
This question is superficially similar, but my relationship isn't polymorphic, so the nominal solution there doesn't help me.
The functionality of :conditions on has_many is to filter the results that are passed back via the graph_labels, not to protect objects from being added to the association.
If you add a graph_label with no label_set_id, the association will build, but if you then ask for graph_pane.graph_labels, it will not return that non-condition-matching graph_label.
The has_many/belongs_to relationship is saved on the belongs_to model, graph_label, and so the parent/has_many/graph_pane does not stop the graph_label from writing whatever it wants to its graph_pane_id attribute. This delegation of responsibility is correct, although frustrating, I agree.
Now, as for how to stop this, I'm not sure. It sounds like you need some sort of validation on the graph_label object, something along the lines of not allowing a graph_pane_id to be set on a graph_label if that graph_label's label_set_id is nil. Since the has_many/belongs_to relationship is saved on the graph_label, you should write the validation on the graph_label. That way, the graph_label will not be able to be saved with a new graph_panel_id unless it fulfills the condition.
Thoughts? Questions?
Reference:
has_many
Alternate Solution
I've reread your question and I think want you want here is a polymorphic association.
def GraphPane < ActiveRecord::Base
has_many :label_sets
has_many :graph_labels, as: :parent
end
def LabelSet < ActiveRecord::Base
belongs_to :graph_pane
has_many :graph_labels, as: :parent
end
def GraphLabel < ActiveRecord::Base
belongs_to :parent, polymorphic: true
end
That way, a GraphLabel can only have a single parent, which is what your “spec” above requires. Is there any reason not to implement the relations in this way?

Rails STI association with subclasses

I'm getting some strange behaviour when fetching collections from a has_many association with rails 3 when using STI. I have:
class Branch < ActiveRecord::Base
has_many :employees, class_name: 'User::Employee'
has_many :admins, class_name: 'User::BranchAdmin'
end
class User < ActiveRecord::Base
end
class User::Employee < User
belongs_to :branch
end
class User::BranchAdmin < User::Employee
end
The desired behaviour is that branch.employees returns all employees including branch admins. The branch admins only seem to be 'loaded' under this collection when they have been accessed by branch.admins, this is output from the console:
Branch.first.employees.count
=> 2
Branch.first.admins.count
=> 1
Branch.first.employees.count
=> 3
This can be seen in the generated SQL, the first time:
SELECT COUNT(*) FROM "users" WHERE "users"."type" IN ('User::Employee') AND "users"."branch_id" = 1
and the second time:
SELECT COUNT(*) FROM "users" WHERE "users"."type" IN ('User::Employee', 'User::BranchAdmin') AND "users"."branch_id" = 1
I could solve this problem by just specifying:
class Branch < ActiveRecord::Base
has_many :employees, class_name: 'User'
has_many :admins, class_name: 'User::BranchAdmin'
end
since they all be found from their branch_id but this creates problems in the controller if I want to do branch.employees.build then the class will default to User and I have to hack at the type column somewhere. I have got around this for now with:
has_many :employees, class_name: 'User::Employee',
finder_sql: Proc.new{
%Q(SELECT users.* FROM users WHERE users.type IN ('User::Employee','User::BranchAdmin') AND users.branch_id = #{id})
},
counter_sql: Proc.new{
%Q(SELECT COUNT(*) FROM "users" WHERE "users"."type" IN ('User::Employee', 'User::BranchAdmin') AND "users"."branch_id" = #{id})
}
but I would really like to avoid this if possible. Anyone, any ideas?
EDIT:
The finder_sql and counter_sql haven't really solved it for me because it seems that parent associations don't use this and so organisation.employees that has_many :employees, through: :branches will again only include the User::Employee class in the selection.
Basically, the problem only exists in the development environment where classes are loaded as needed. (In production, classes are loaded and kept available.)
The problem comes in due to the interpreter not having seen yet that Admins are a type of Employee when you first run the Employee.find, etc. call.
(Notice that it later uses IN ('User::Employee', 'User::BranchAdmin'))
This happens with every use of model classes that are more than one level deep, but only in dev-mode.
Subclasses always autoload their parent hierarchy. Base classes don't autoload their child hierachies.
Hack-fix:
You can force the correct behaviour in dev-mode by explicitly requiring all your child classes from the base class rb file.
Can you use :conditions?
class Branch < ActiveRecord::Base
has_many :employees, class_name: 'User::Employee', :conditions => {:type => "User::Employee"}
has_many :admins, class_name: 'User::BranchAdmin', :conditions => {:type => "User::BranchAdmin"}
end
This would be my preferred method. One other way to do it might be to add a default scope to the polymorphic models.
class User::BranchAdmin < User::Employee
default_scope where("type = ?", name)
end
A similar problem continues to exist in Rails 6.
This link outlines the issue and workaround. It contains the following explanation and code snippet:
Active Record needs to have STI hierarchies fully loaded in order to generate correct SQL. Preloading in Zeitwerk was designed for this use case:
By preloading the leaves of the tree, autoloading will take care of the entire hierarchy upwards following superclasses.
These files are going to be preloaded on boot, and on each reload.
# config/initializers/preload_vehicle_sti.rb
autoloader = Rails.autoloaders.main
sti_leaves = %w(car motorbike truck)
sti_leaves.each do |leaf|
autoloader.preload("#{Rails.root}/app/models/#{leaf}.rb")
end
You may require a spring stop for the configuration changes to take.
Indeed, that was the plan in the early days of the gem, but it was abandoned soon (in 2019, before Rails 6 was out). Preloading has been deprecated for a long time, and has been deleted in the forthcoming Zeitwerk 2.5.
In a Rails application you can do it this way:
# config/initializers/preload_vehicle_sti.rb
Rails.application.config.to_prepare do
Car
Motorbike
Truck
end
That is, you "preload" just by using the constants in a to_prepare block.

Filter based on model attribute has_many relationship through, rails 3?

I have a simple question, but can't seem to find any solution, though I have found things that are similar, but just not exactly what I am looking for.
I have an application where a User has many Assets through the class UserAsset. I want to be able to do current_user.user_assets , but I only want to return records that have an Asset with a specified field value of "active".
This post is similar but I need to use the main model not the join model as a filter.
class UserAsset < ActiveRecord::Base
belongs_to :asset
belongs_to :user
end
class Asset < ActiveRecord::Base
has_many :user_assets
has_many :users, :through => :user_assets
end
class User < ActiveRecord::Base
has_many :user_assets
has_many :assets, :through => :user_assets
end
I tried setting the default scope on Asset, and also some conditions on the has many (user_assets) relationship, but rails is failing to consider the join on the Assets table. ie Unknown column 'asset.live' in 'where clause'. Trying to achieve the following:
#active_user_assets = current_user.user_assets #only where assets.active = true
So how do I use conditions or scopes to achieve this? I need the user_asset object because it contains info about the relationship that is relevant.
Thanks in advance!
You want current_user.assets, then your scopes should work.
Oh, but you want the user_assets. Hmm. I think you need the :include clause to find() but where to put it, I can't be arsed to think of right now.
Perhaps
current_user.user_assets.find(:all, :include => :assets).where('asset.live=?', true)
(I'm not on Rails 3 yet, so that's going to be mangled)
Are you using :through when you really want a HABTM?

Rails: Make different references to a DB row refer to the same Ruby object

Suppose I have the following model relationship:
class Player < ActiveRecord::Base
has_many :cards
end
class Card < ActiveRecord::Base
belongs_to :player
end
I know from this question that Rails will return me a copy of the object representing a database row, meaning that:
p = Player.find(:first)
c = p.cards[0]
c.player.object_id == p.object_id # => false
...and therefore if the Player model modifies self, and the Card model modifies self.player in the same request, then the modifications won't take any notice of each other and the last-saved one will overwrite the others.
I'd like to work around this (presumably with some form of caching), so that all requests for a Player with a given id would return the same object (identical object_ids), thereby allowing both models to edit the same object without having to perform a database save-and-reload. I have three questions:
Is there already a plugin or gem to do this?
Are there good reasons why I shouldn't do this?
Can anyone give me some pointers on how to go about doing this?
This is supported in Rails 3.x. You can use the :inverse_of option for the has_many association for example. Documentation here (search for :inverse_of and Bi-directional associations).