I am using Rails 3 and want whenever user will be created, then separate Data Base should be created for newly created user.
e.g if I have 13 migration in my application, so 13 tables should be created for newly created user.
How I can achieve this functionality?
Also check out the audio/video that goes along with James slides here http://www.confreaks.com/videos/889-railsconf2012-ten-things-you-didn-t-know-rails-could-do. Move forward to around 15:30 for the section on one user per database.
This is a really bad idea to handle many DB in Rails!
You can add a field, say, user_id in each of your tables that are needed to be separated and then apply default_scope to their respective models (or make an abstract model with default_scope via self.abstract_class = true and inherit your "shareable" models from it).
Your default_scope, as you might guess, should look like:
default_scope lambda { where(user_id: current_user_id) }
How to get the current user, you may ask?
Models can't access session, so you can make the following "hack" in order your scope to work:
#in ApplicationController
before_filter do
user_id = session[:user_id]
ActiveRecord::Base.class.send :define_method, :current_user_id, lambda { user_id }
end
I guess you got the idea.
This is best post i follow and solve my problem
http://7fff.com/2010/12/02/activerecord-dropcreate-database-run-migrations-outside-of-rails/
Related
How do I associate two entries in a database that are connected through a many-to-many relationship in Rails?
I'm trying to associate Users and Issues for an issue tracker. I'm using has_and_belongs_to_many, not :through. I have a :user_id and :issue_id available to me, but there doesn't seem to be User.issues.find(id) or Issue.users.find(id) available to me. I have a route post "/", to: "home#create". I'm trying to make a create method in home_controller.rb.
From the look of it you're calling the method on the User class and not an instance.
If you want to get the issues connected to a user you need to fetch the user first:
User.find(id).issues
If you want to add a record to the association you can use the shovel method or any of the methods generated by the association macro:
User.find(id).issues << Issue.find(3)
User.find(id).issues.push(Issue.find(3))
User.find(id).issue_ids = [1, 2, 3]
Besides that you have a smattering of naming issues in your schema. Use snake_case everywhere in your database schema unless you have a good reason why you want to break the conventions and feel like explicitly configuring table and foreign key names.
I would also really question if you really want to use has_and_belongs_to_many. It should only really be used if you can't foresee that you ever will need to add additional attributes to the join table or never need to query the table directly - it seems pretty unrealistic that that would be true in an issue tracker. You want has_many through: - pretty much always.
I have a route post "/", to: "home#create". I'm trying to make a
create method in home_controller.rb.
Don't throw everything into a junk drawer controller. Think about your app in terms of resources that can be CRUD:ed and create controllers that handle just that resource. You should think about what the relation between a user and an issue is in your domain and how you can model it as an actual entity in the domain logic instead of just plumbing.
Maybe all I need to do is direct you to Rails Guides: Active Record Associations.
There is neither of these
User.issues.find(id)
Issue.users.find(id)
because when you are finding an issue or user by id, you don't use the association. Instead use these:
Issues.find(id)
Users.find(id)
Since the :id is unique this will work and should be what you want.
The only time you want to query issues or users using the association will be when you have the data for the other end of the relationship.
user = User.find(user_id)
issue = user.issues.where(id: issue_id)
Since the :id field is unique, this is the same as Issues.find(id). However if you want to get a collection of a user's issues with some other data, you can put the condition for that data in the where.
You can create an issue for a user this way:
user = User.find(user_id)
issue = User.issues.create( ... )
I have a Model Bot and I would like to ensure that there is only one Bot object in my database. I also need to make sure it is persisted and not tampered with.
My original thought was to do this in a migration, one that would follow the :bots table migration. It would include a line that is something like:
Bot.all.size == 0 ? Bot.create! : nil
Maybe this would prevent the AR object from being messed with in future migrations?
BONUS: Would be awesome to be able to have instant and global access to this class object. I was thinking using a singleton module in my Bot class that way I can always reference Bot.instance and have access to that specific object.
USE CASE:
I have 4 types of users in my DB and this bot will be the facilitator to delivery role-specific messages to them through our in-app messaging feature.
The Class Bot will have a has_many association with BotMessage/bot_messages. On the bot_messages table will be an enum field for user_role.
Messages will be created by company admins and stored in these tables because we want them to be viewable at any time by looking at the "conversation" thread between the User and the Bot.
When it comes to only having 1 bot, it's just that. I have no need for an additional Bot object. Additionally, since there is only one object it would be nice to be able to have a way of explicitly targeting that object without having to run a query to find it.
For example, unlike User where there could be 1000 records and in order to find the specific one you would do something like #user = User.find_by_email('foo#bar.com'), doing something like that for the bot would be unnecessary since there is only one record to find. That is what lead me to believe having a singleton object may be worthwhile here, so whenever I need to pull up a message for a specific role, I could run Bot.instance.bot_messages.where(user_role: 1) or something similar
Based on your Use Case, I see no reason for Bot to be a model.
Let's say you have a role called cool_user and you want to get all the bot_messages for that role, you might do something like:
class Bot
class << self
def bot_messages(user_role)
BotMessage.send(user_role)
end
end
end
As a very thoughtful but potentially anonymous super code monkey notes in the comments, you could also do:
class Bot
def self.bot_messages(user_role)
BotMessage.send(user_role)
end
end
Which some folks might find more readable. IMO, it is a bit of an issue of personal preference.
In either case, you should be able to do
Bot.bot_messages(:cool_user)
Since, as stated in the docs,
Scopes based on the allowed values of the enum field will be provided as well.
So, I believe BotMessage, with the properly set enum, should respond to cool_user and return all the bot_messages for that role.
You may need to check the docs to get the syntax exactly right.
I believe this should also satisfy your BONUS requirement.
A proven solution would be to use an STI on User (with a user_type column)
class User < ApplicationRecord
...
end
class Bot < User
has_many :bot_messages, foreign_key: :user_id
end
Is it what you're looking for ?
I would like to create some sample data for a user when they register so that they do not have to start with a blank canvas.
I am presently defining lots of static data in classes which I then iterate over, however setting up relationships is cumbersome and I think that this is quite brittle.
I think that having some demo fixtures (separate from my test set) would be a good way to do this, but as records are tied to an account I can't see how I can insert this data and attach it to the account when loading the fixtures.
This might not even be the best approach, but if there is a better way then please let me know.
Every RAILS application has seeds.rb present in db/ folder.So as the name says,it is used to seed your db by default records that you may want.
So this is how i am using my seeds.rb.Creating many records,constants and then to put those records in your db,just run rake db:seed assuming you have db ready.See HERE for more infor
my seeds.rb
###seed eventype table with default values
["birthday","farewell","party"].each do |f|
EventType.find_or_create_by({name:f.upcase})
end
###create users with random names
##after creating users,create associated fields
%w[mike john paul allen harry betty].each_with_index do |name,index|
#user = User.find_or_create_by({email:"user_#{name}#gmail.com"})
##user has_one address
#user.create_address({:address_2=>"street 1,near berry lane"})
##user has_many pictures
#user.pictures.create!({:title=>"Title of the picture",:picture => File.new("#{Rails.root}/public/images/test.jpg")})
end
You can even use (0..6).each do loop to create n records as you wish in db.
for example:-
(0..100).each do
###create user/pictures etc
end
However you must be careful to follow all validations and create valid record else this wont work.
for example,if in user model,you are expecting username as well,then in seeds.rb,you must pass the username so that it passes the validation easily.
=========================================================================
IF you dont want to use db seed,you can use a callbacks on: :create(i dont prefer observers).Simple example can be :
##in user.rb
after_commit :create_default_account, on: :create
def create_default_account
##assuming user has_one :account
self.build_account({:name=>"Default account"})
end
HOPE IT HELPS
My Rails app has many models that form a hierarchy. For example: Retailer > Department > Product Category > Product > Review.
A business requirement is that high-authority users can "share" any individual element in the hierarchy with a new or existing "normal" user. Without having an object shared with them, normal users have no rights to see (or do anything else) with any object in any level of the hierarchy.
The sharing process includes a choice of whether the share grants permission to read-only, read-update, or full CRUD on the target object.
Sharing any object grants R/O, R/W or CRUD permission to that object and all lower level objects in the hierarchy, and R/O permission to all of the direct ancestors of the object. The object collection grows organically, so the permission system works by just logging the user_id, the object_id of the share, and the nature of the share (R/O, CRUD, etc). As the population of objects in this hierarchy grows all the time, it is impractical to create an explicit permission record in the DB for every user/object combination.
Instead, at the start of the user request cycle, ApplicationController gathers all the permission records (user X has CRUD permission to Department #5) and holds them in a hash in memory. A Permissions model knows how to evaluate the hash when any object is passed to it - Permission.allow?(:show, Department#5) would return true or false depending on the content of the user's permission hash.
Let's take, for example, the Department model:
# app/models/department.rb
class Department < ActiveRecord::Base
after_initialize :check_permission
private
def check_permission
# some code that returns true or false
end
end
When the check_permission method returns true, I want Department.first to bring back the first record in the database as normal, BUT, if check_permission returns false, I want to return nil.
Right now, I have a solution whereby default scopes trigger a permissions check, but this is causing 2X the number of queries, and for classes with a lot of objects, memory problems and time/performance issues are sure to be on the horizon.
My goal is to use after_initialize callbacks to pre-permission the objects.
It would appear however that after_initialize is unable to block the original object from being returned. It does allow me to reset the values of the attributes of the object, but not to dispense with it.
Anybody know how to achieve this?
EDIT:
Many thanks for all of the answers and comments offered so far; hopefully this extended version of the question clarifies things.
Basically you need to check for access rights (or permissions) before returning a database query result. And you are trying to integrate this logic into your models.
It is possible, but not with the design you described in your question. It is not clean to implement this directly in ActiveRecord adapter methods (such as first, all, last etc...). You need to rethink your design.
(skip to point 'D' if this is too much reading)
You have several choices, which all depend on the way your permissions are defined. Let's look at few cases:
A. A user have a list of departments he owns and only him can access them
You can simply implement this as a has_many/belongs_to association with Active Record Associations
B. Users and Departments are independent (in other words: no ownership such as described in the previous case) and permission can be set individually for each users and each departments.
Simply again, you can implement a has_and_belongs_to_many association with Active Record Associations. You will need to create web logic so the administrator of your application can add/edit/remove access rights.
C. More complex case: the existing authorization libraries
Most people will turn to authorization solutions such as cancan, pundit or other
D. When those authorization libraries are oversized for your needs (actually, my case in most of my projects), I found that implementing authorization through rails scoping answers all my needs.
Let's see it through a simple example. I want administrators to be able to access the whole database records ; and regular users to access only departments with status = open and only during operation hours (say 8am-6pm). I write a scope that implement my permission logic
# Class definition
class Department
scope :accessible_by -> (user) do
# admin user have all access, always
if user.is_admin?
all
# Regular user can access only 'open' departments, and only
# if their request is done between 8am and 6pm
elsif Time.now.hour >= 8 and Time.now.hour <= 18
where status: 'open'
# Fallback to return ActiveRecord empty result set
else
none
end
end
end
# Fetching without association
Department.accessible_by(current_user)
# Fetching through association
Building.find(5).departments.accessible_by(current_user)
Defining a scope obliges us to use it everywhere in our code. You can think of the risk to "forget" going through the scope and accessing directly the model (i.e writing Department.all instead of Department.accessible_by(current_user)). So that's why you must solidly test your permissions in your specs (at the controller or features level).
Note In this example we do not return nil when the permission fails (as you mentioned in your question), but an empty result set instead. It is generally better so you keep the ActiveRecord method chaining capability. But you could also raise an exception and rescue it from your controller then redirect to a 'not authorized' page for example.
That is not what the after_initialize callback is used for. Instead, you could just define a method that does the same thing. For example, put this in your Department model and it should achieve the results you are looking for:
def self.get_first
check_permission ? first : nil
end
UPDATE
I'm not exactly sure how safe something like this would be, but you could just override the all method as the other query methods are based off of it.
class Department < ActiveRecord::Base
def self.all
check_permission ? super : super.none
end
private
def self.check_permission
# some code that returns true or false
end
end
You are probably better off using some authorization framework though.
UPDATE 2
Thinking about this a little more, I strongly recommend using a different approach. You really shouldn't be overriding methods like all as there will surely be unintended side effects.
A practical alternative would be to create a has_and_belongs_to_many relationship between Department and User. Here is how you would set it up:
user.rb
class User < ActiveRecord::Base
has_and_belongs_to_many :departments
...
end
department.rb
class Department < ActiveRecord::Base
has_and_belongs_to_many :users
...
end
Then run these commands in your terminal:
rails g migration CreateJoinTableDepartmentsUsers departments users
rake db:migrate
Now you can add users to a department with #department.users << #user, or departments to a user with #user.departments << #department. This should achieve the functionality that you are looking for.
#user.departments will return only departments for that user, #user.departments.first will return the first department for that user or nil if it doesn't have any, and #user.departments.find(1) will return the corresponding department only if it belongs to the user or throw an exception otherwise.
You can use before_create callback to stop record creation if check permission is false. Just return false in check_permission filter and record will be not created.
class Department < ActiveRecord::Base
before_create :check_permission
private
def check_permission
# return false if permission is not allowed
end
end
I would like to populate various tables in my database after a new customer signs up to use our web application. I'm wondering what the best way to do this is, the main requirement being that it should not require any intervention by me. Most of the data is static (but can be changed by the customer later (like preferences for example)), but will obviously need the customer's ID as a way of linking the created records to this customer.
I considered putting a few
Object.create(:customer_id => #customer.id, :yummy => "maybe", :etc => true)
statements in the controller that handles signups, but that annoying little alarm bell that tells me there's a better way is going off again!
Thanks in advance for any suggestions!
Gav
The problem with khelll's solution is that if you create a new Account using from outside of the register action (for example, in an admin module), it's database won't be populated.
So I'd prefer something like the following :
class Account < ActiveModel::Base
def after_create
populate
end
private
def populate
# Your logic
end
end
The after_create callback will be called after any account creation.
That's more MVC and DRY compliant ;)
In your controller
class AccountController < ApplicationController
after_filter :populate_db :only=>[:register]
def populate_db
# whatever stuff
Account.populate
end
end
And put the logic inside your model:
class Account < ActiveModel::Base
def populate
# your logic
end
end
two ways
a trigger function in your database that does this
a callback in your user model on creation
Can you not just set defaults in your database?
I'm using a YAML file to populate more than ten tables in database during signup. This approach has some positive side-effects for me:
I can easily change the contents of the seed data for new account
It is very easy to add localized versions of initial content, i can let YAML files translated easily through 99translations.com
I'm planning to add data import feature later on where new clients can import their data during or right after signup so they can just take the import file template and customize it for their own needs.
There have been some downsides too:
Inevitably, when data schema changes, sometimes i have to modify all localized versions of these files.
It is one piece of ugly code i have that maps the foreign keys between all the new records. Maybe i can use some schema descriptors here...
As i get around 300 new signups in a day, it's too early for me to worry about performance.
#Omar Qureshi
You shouldn't use trigger function in your database - there are many features that can be done by them, but ActiveRecord is database-agnostic and it has callbacks that handle such things that triggers can. Using something that links you to a specific DB system is wrong.
#dmathieu's answer seems to be the best. And you should consider using Factory girl - it's a great tool for populating the DB.