relation "admin_keywords" does not exist` - ruby-on-rails

I want to have scaffold actions for Keywords table as admin. This code begins to work after I restart the server and Remove Admin:: from /app/models/admin/keyword.rb, then refresh website, get error and adding Admin:: to model again. From that moment everything works fine. But after server Starts, I got this: (Rails 4)
PG::UndefinedTable: ERROR: relation "admin_keywords" does not exist
/app/controllers/admin/keywords_controller.rb source:
class Admin::KeywordsController < ApplicationController
def index
#keywords = Admin::Keyword.all
end
end
/app/models/admin/keyword.rb source:
class Admin::Keyword < ActiveRecord::Base
end
going to url:
http://localhost:3000/admin/keywords
routes.rb:
namespace :admin do
resources :keywords
end
How to fix this error?

If you add namespace to your models, database table should contain this namespace too. For example model Admin::Keyword is related with admin_keywords table.
You can override model's table defining self.table_name='your_table_name' method in model.
class Admin::Keyword < ActiveRecord::Base
self.table_name = 'your_table_name'
end

Related

superclass mismatch for class User - inheriting from ActiveRecord::Base

I am trying to figure out my superclass mismatch error. All the posts I've read about this describe the problem as being that User is defined twice as a class in my application.
In my case, it isn't defined twice. I have a services folder and within that I have a user folder (for user service classes). In that user folder, I have a file called organisation_mapper_service.rb, with:
class User < ActiveRecord::Base
class OrganisationMapperService
def self.call(user: u)
new(user: user).call
end
def initialize(user: u)
self.user = user
end
def call
if matching_organisation.present?
# user.organisation_request.new(organisation_id: matching_organisation.id)
# user.update_attributes!(organisation_id: matching_organisation.id)
else
#SystemMailer.unmatched_organisation(user: user).deliver_now
end
end
private
attr_accessor :user
def matching_organisation
User::OrganisationMapperService.new(user).matching_organisation
end
end
end
Separate to that, I have my user model which defines user as:
class User < ApplicationRecord
I thought it should be fine to define the service class in the way I have because it inherits from ActiveRecord::Base rather than ApplicationRecord.
Can anyone see what I've done wrong here? Where else could I look for a second definition of User?
TAKING SERGIO'S SUGGESTION
I change the user organisation mapper service to open as follows:
class User::OrganisationMapperService < ActiveRecord::Base
But that then gives an error with my Users::OrgRequestsController which has new defined as follows:
def new
#all_organisations = Organisation.select(:title, :id).map { |org| [org.title, org.id] }
#org_request = OrgRequest.new#form(OrganisationRequest::Create)
matched_organisation = User::OrganisationMapperService.new(current_user).matching_organisation
#org_request.organisation_id = matched_organisation.try(:id)
end
the error message then says:
PG::UndefinedTable at /users/4/org_requests/new
ERROR: relation "user_organisation_mapper_services" does not exist
LINE 8: WHERE a.attrelid = '"user_organisation_mapper...
**TAKING SERGIO'S SUGGESTION (exactly) **
I change my service class to:
class User::OrganisationMapperService
But then I get an error that says:
wrong number of arguments (given 1, expected 0)
That error highlights this line of my service class:
def initialize(user: u)
self.user = user
end
I don't know what to do about that because I clearly have a user if there is an inheritance from user.
Even once you solve all your other issues, you actually have an infinite recursion going on.
User::OrganisationMapperService.call(user: User.first)
Is equivalent to calling:
User::OrganisationMapperService.new(user: User.first).call
Which internally calls matching_organisation, so is sort of equivalent to:
User::OrganisationMapperService.new(user: User.first).matching_organisation
Meanwhile, matching_organisation calls
User::OrganisationMapperService.new(user).matching_organisation
It's just going to go round and round in circles.
The only reason it doesn't is because of the wrong number of arguments (given 1, expected 0) error. This is because it should be User::OrganisationMapperService.new(user: user) rather than User::OrganisationMapperService.new(user) in your matching_organisation method.
Update in response to comment:
From what I understand, the User::OrganisationMapperService is a service class that does the job of finding some Organisation and then performing some sort of work.
The User::OrganisationMapperService#matching_organisation method should actually contain the code that returns the matching organisation for the given user. The implementation will completely depend on how you have structured your database, but I'll give a couple of examples to put you on the right track or give you ideas.
First, Your organisations table may have a user_id column. In this case you could do a simple query on the Organisation model and perform a search using the user's id:
class User::OrganisationMapperService
def matching_organisation
# find the organisation and cache the result
#matching_organisation ||= ::Organisation.where(user_id: user).first
end
end
Alternatively, you may have some sort of join table where there may be multiple Users at an Organisation (just for this example let us call this table 'employments'):
class Employment < ApplicationRecord
belongs_to :user
belongs_to :organisation
end
We can add scopes (this is a must read) to the Organisation model to assist with the query:
class Organisation < ApplicationRecord
has_many :employments
has_many :users, through: :employments
scope :for_user, ->(user) {
# return organisations belonging to this user
joins(:users).merge( Employment.where(user_id: user) )
}
end
Then finally, the OrganisationMapperService#matching_organisation method becomes:
class User::OrganisationMapperService
def matching_organisation
# find the organisation and cache the result
#matching_organisation ||= ::Organisation.for_user(user).first
end
end
You are defining User class with two separate parent classes. Don't do that.
It should be
class User::OrganisationMapperService
This way, your existing User class will be loaded and used, rather than a new one created.
I thought it should be fine to define the service class in the way I have because it inherits from ActiveRecord::Base rather than ApplicationRecord.
The service class in your example doesn't inherit from anything.

How to create controllers in different namespace for an existing model?

I have a Product model in my rails app. Now I want to create a controller and views for this product model through scaffolding in a different namespace(api).
Till now I have tried using
rails g scaffold_controller product name:string price:integer
and after this I added the this to my routes file
namespace :api do
resources :products
end
Now when I go to the link api/products . I get this error
uninitialized constant Api::Product
on the index action
def index
#api_products = Api::Product.all
end
After this I removed the Api:: from my controller index, new and create action. After doing this my index url (/api/products) was working fine but now when I try to create a new product(/api/products/new) I get the following error
undefined method `products_path'
This is the code for my model file (location is models/)
class Product < ActiveRecord::Base
end
Can anyone please help in implementing this correctly?
You should move product.rb to app/models/api and change the class name to Api::Product
#app/models/api/product.rb
class Api::Product < ActiveRecord::Base
self.table_name = "products"
end

Rails STI - same records for sub-sub-class

Models:
class User < ActiveRecord::Base
end
class Admin < User
end
class SpecialAdmin < Admin
end
I would like SpecialAdmin to have the same records/dataset as Admin model. Each SpecialAdmin record could for example have "Admin" in its type column when edited/created - any other similar solution would be fine too.
I tried this
self.inheritance_column :nil # Didnt work because it fetches all records in the table
...becomes method # Didnt get this to work either
Thanks for any input!

Rails: Creating Wrong Table Name With a Namespaced STI

I have a model which uses STI:
class Contributor::Name < Contributor::NameBase
...
end
From this model:
class Contributor::NameBase < ActiveRecord::Base
...
end
Whenever Contributor::Name gets instantiated, I receive this error:
Mysql2::Error: Table 'shelflives_development.contributor_basis_name_bases' doesn't exist: SHOW FULL FIELDS FROM `contributor_basis_name_bases`
It seems that instead of looking up the table contributor_name_bases, ActiveRecord is looking up contributor_basis_name_bases. Why is adding basis between contributor and name_bases? How can I get it to stop?
Ok, it's not a answer about why rails is adding 'basis' but it will work for you.
Use set_table_name 'contributor_name_bases' in your model.

Rails 3 - Multiple database with joins condition

My environment: Ruby 1.9.2p290, Rails 3.0.9 and RubyGem 1.8.8
unfortunately I have an issue when come across multiple database.
The situation is this: I have two model connect with two different database and also establishing association between each other.
database connection specifying in each model, look likes
class Visit < ActiveRecord::Base
self.establish_connection "lab"
belongs_to :patient
end
class Patient < ActiveRecord::Base
self.establish_connection "main"
has_many :visits
end
I got an error when meet following scenario
#visits = Visit.joins(:patient)
Errors: Mysql2::Error: Table 'lab.patients' doesn't exist: SELECT visits.* FROM visits INNER JOIN patients ON patients.id IS NULL
Here 'patients' table is in 'main' database and 'visits' table in 'lab' database
I doubt when executing the code, that Rails is considering 'patients' table is part of 'lab' database [which holds 'visits' table].
Well, I don't know if this is the most elegant solution, but I did get this to work by defining self.table_name_prefix to explicitly return the database name.
class Visit < ActiveRecord::Base
def self.table_name_prefix
renv = ENV['RAILS_ENV'] || ENV['RACK_ENV']
(renv.empty? ? "lab." : "lab_#{renv}.")
end
self.establish_connection "lab"
belongs_to :patient
end
class Patient < ActiveRecord::Base
def self.table_name_prefix
renv = ENV['RAILS_ENV'] || ENV['RACK_ENV']
(renv.empty? ? "main." : "main_#{renv}.")
end
self.establish_connection "main"
has_many :visits
end
I'm still working through all the details when it comes to specifying the join conditions, but I hope this helps.
Might be cleaner to do something like this:
def self.table_name_prefix
"#{Rails.configuration.database_configuration["#{Rails.env}"]['database']}."
end
That will pull the appropriate database name from your database.yml file
Or even
def self.table_name_prefix
self.connection.current_database+'.'
end
Is your 2nd database on another machine? You can always do as suggested in this other question:
MySQL -- Joins Between Databases On Different Servers Using Python?
I'd use the self.table_name_prefix as proposed by others, but you can define it a little more cleanly like this:
self.table_name_prefix "#{Rails.configuration.database_configuration["#{Rails.env}"]['database']}."
alternatively you could also use this:
self.table_name_prefix "#{connection.current_database}."
You have to keep in mind that the latter will execute a query SELECT DATABASE() as db the first time that class is loaded.

Resources