I've got 2 models, band and genre, and a many-to-many relation via an association table bands_genres (which doesn't have a model) the following way.
class Genre < ActiveRecord::Base
has_and_belongs_to_many :bands
class Band < ActiveRecord::Base
has_and_belongs_to_many :genres
Checking out the output logs of my app, I see that every call involving bands or genres end up doing this query:
SQL (1.8ms) describe `bands_genres`
Why is this happening? How could I cache somehow the result of this query to avoid doing it on each request?
Run your server in production mode. Table information is reloaded on each request when in development mode.
rails s -e production
It's because your current environment configuration tells Rails to do so. I assume you use "development", but you do have "production", and "test" also.
There is an option to cache classes in any of your envs' configuration. Check the current one (I assume you use "development"):
config/environments/development.rb
and modify this option to true:
# 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 = true
Then, run server with your current environment. For development:
bundle exec rails s
is enough.
This does 2 things:
1) when Rails start, it will now read all classes' definitions
(models) up front, and keep it for each request.
When you change a class now, no code will be reloaded automatically
2) Rails will not ask database for model metadata change,
so no "describe table" will go to database in any request
"Production" env by default has this option set to "true". But "production" env is meant for production and not development. You may specify different options, urls, vars there..
Related
I am trying to create a simple application using Grails(3.2) and MySQL in Netbeans.
I have configured MySql in Grails project and also created a database, named "third" . After creating the domain class model, the controller (scaffolded) and the views for CRUD, my project is running but whenever I am trying to do any operation -
screenshot of error
this error is occuring. I am unable to solve this problem and also tried manually creating "Person" table, but same error occuring.
Your stacktrace clearly states that your db with name third doesn't have proper table person. But you shouldn't create this table manually (if you already had - please remove all tables from your db)
Connection seems fine but you should take a look at dbCreate value in your application.yml.
dbCreate - Whether to auto-generate the database from the domain model
- one of 'create-drop', 'create', 'update' or 'validate'
https://docs.grails.org/latest/guide/conf.html
If you are using just simple command grails run-app to start server, then you should check out the value in the environments: development block.
Paste your application.yml content (without db credentials) if you need a personalized solution.
I have a single client application - Angular JS frontend and a Rails API backend with a MySQL DB. I'm trying to convert the application into a single schema multi tenant application. I've done a lot of reading and:
I do not want to use a gem if possible - Apartment, which is multiple schemas and uses Postgres doesn't fit the bill, and act_as_tenant seems to use Thread.current to identify the tenant which I do not want to do.
I have read that default_scope should not be used as well, for a host of reasons I won't get into here.
I'm passing a tenant token in the request header from the frontend to the Rails backend, and using the tenant token I identify the tenant in my ApplicationController. I'm now figuring out the best way to both read and write data so that is associated with the tenant that made the request.
Having ruled out the options above, the only option I can see is to go into all of my controller methods and update them wherever data is being written and read. I would much rather apply some sort of callback to each of my Models, so that the tenant id is always written when data is being written and the tenant id is always used as a filter whenever data is being read.
Given that I cannot access the tenant token in the models, I am not sure how to proceed with this other than updating all my controller methods, which would be an arduous and mistake prone process.
Thanks in advance!
Not using default_scope is a good idea - it behaves as sort of a black box and can wreck havoc down the line especially if you ever do anything with paranoid deletion.
One way to do what you asked is to use thread_mattr_accessor. You can define the tenant_id token at the beginning of the web request, and then access it through the class attribute for the duration of the web request. This creates a thread-safe attributes accessor on your tenant model.
In your controller you can detect the tenant for the current request (using subdomain or token) and set the Token.current_id variable. This variable will be available for the duration of the request. Note that it will not automatically be available for any background jobs or other processes because the variable is set inside the current thread.
This method is demonstrated using scopes in this RailsCast, but you don't have to use scopes. You can set a helper method like current_tenant and then explicitly scope all your queries like current_tenant.posts.
# models/tenant.rb
class Tenant < ApplicationRecord
thread_cattr_accessor :current_id
# ...
end
# controllers/application_controller.rb
class ApplicationController < ActionController::Base
around_action :scope_current_tenant
private def scope_current_tenant
Tenant.current_id = current_tenant.id
yield
ensure
Tenant.current_id = nil
end
def current_tenant
#current_tenant ||= Tenant.find_by_token! params[:token]
end
helper_method :current_tenant
end
I want to implement a tracking system for monitoring users' activity within the application.
The application is currently used within the business hours by about 600-2000 users.
I originally wanted to use a before_filter to the ApplicationController where every time a user would click a link, I'd save information such as user/admin id, params[:controller], params[:action] and other params of actions to the database. (I know about gems like audited - but not sure if I use them).
However I am wondering if I basically don't kill the app when for every click within the system will be called database to insert some data into it.
I was thinking of using a background method (sidekiq) for logging the action into the database.
Basically:
class ApplicationController
before_filter :log_request
def log_request
RequestLogger.perform_async(params[:controller], params[:action], current_user.id)
end
end
class RequestLogger
include Sidekiq::Worker
def perform(controller, action, user_id)
# Save data to the database
end
end
More or less.
I'd urge you to use a logfile. Compresses easily and then you can process entire logfiles in a batch. Just update Rails to log the session ID and you can track individual sessions.
We have a system where we have a Master / Multiple Slaves .
Currently everything happens on the Master and the slaves are just here for backup .
We use Codeigniter as a development platform .
Now we decided to user the slaves for the Reads and the Master for the Write queries .
I have been told that this is not doable without modifying the source code because proxy can't know the type of the query .
Any idea how to proceed with this without causing too much damages for a perfectly working system ...
We will use this : http://dev.mysql.com/downloads/mysql-proxy/
It does exactly what we want :
More info here :
http://jan.kneschke.de/2007/8/1/mysql-proxy-learns-r-w-splitting/
http://www.infoq.com/news/2007/10/mysqlproxyrwsplitting
http://archive.oreilly.com/pub/a/databases/2007/07/12/getting-started-with-mysql-proxy.html
something i was also looking, few month back i did something like this but i added 3 web server with master slave mysql servers, first web server enabled with mod_proxy to redirect request to read and write server all request will come to this server, if post,put or delete request come to server it will go to write server, all get or normal request will go to read server
here you can find mod_proxy setting which i used
http://pastebin.com/a30BRHFq
here you can read about load balancing
http://www.rackspace.com/knowledge_center/article/simple-load-balancing-with-apache
still looking for better solution with less hardware involved
figure out another solution through CI, create two database connections in database.php file keep save mysql server as default database connection and other connection for write only server
you can use this base model extend
https://github.com/jamierumbelow/codeigniter-base-model
you need to extend your models with this model and need to extend you model with this, it has functionality for callbacks before and after insert,update, delete and get queries, only you need to add one custom method or callback change_db_group
//this method in MY_Model
function change_db_group{
$this->_database = $this->load->database('writedb', TRUE)
}
no your example model
class Example_Model extends MY_Model{
protected $_table = 'example_table';
protected $before_create = array('change_db_group');
protected $before_update = array('change_db_group');
protected $before_delete = array('change_db_group');
}
you database connection will be changed before executing insert,update or delete queries
It only happens in production, when we update some of the records through browser, the change was not saved. it does not seem to be a cache problem as we verified that the data in mysql was still the old data. However, the controller did get hit and flash message returned as if the change was made successfully.
However, we can make the change manually in rails console or mysql withhout any problem.
Any ideas why this is happening?
btw, we recently reconfigure the site to use SSL, it might have something to do with that.
Is there anything that could've prevented the model from being saved?
One way to ensure that the attributes are set and the model is saved is to use the exception raising version which can help fix problems like this:
def update
#model = Model.find(params[:id])
#model.update_attributes(params[:model])
redirect_to(model_path(#model))
end
This could be improved to a more reliable method:
def update
#model = Model.find(params[:id])
# Use exception-throwing update_attributes!
#model.update_attributes!(params[:model])
redirect_to(model_path(#model))
rescue ActiveRecord::RecordNotFound
render(:partial => 'not_found')
rescue ActiveRecord::RecordInvalid
# Delegate back to edit action, something's invalid
edit
render(:action => 'edit')
end
There are occasions where update_attributes may not successfully save.
If you can perform the same update on the same data with the same methods then that is peculiar.