Deleting all records in a database table - ruby-on-rails

How do I delete all records in one of my database tables in a Ruby on Rails app?

If you are looking for a way to it without SQL you should be able to use delete_all.
Post.delete_all
or with a criteria
Post.delete_all "person_id = 5 AND (category = 'Something' OR category = 'Else')"
See here for more information.
The records are deleted without loading them first which makes it very fast but will break functionality like counter cache that depends on rails code to be executed upon deletion.

To delete via SQL
Item.delete_all # accepts optional conditions
To delete by calling each model's destroy method (expensive but ensures callbacks are called)
Item.destroy_all # accepts optional conditions
All here

if you want to completely empty the database and not just delete a model or models attached to it you can do:
rake db:purge
you can also do it on the test database
rake db:test:purge

If you mean delete every instance of all models, I would use
ActiveRecord::Base.connection.tables.map(&:classify)
.map{|name| name.constantize if Object.const_defined?(name)}
.compact.each(&:delete_all)

BlogPost.find_each(&:destroy)

If your model is called BlogPost, it would be:
BlogPost.all.map(&:destroy)

More recent answer in the case you want to delete every entries in every tables:
def reset
Rails.application.eager_load!
ActiveRecord::Base.descendants.each { |c| c.delete_all unless c == ActiveRecord::SchemaMigration }
end
More information about the eager_load here.
After calling it, we can access to all of the descendants of ActiveRecord::Base and we can apply a delete_all on all the models.
Note that we make sure not to clear the SchemaMigration table.

If you have model with relations, you need to destroy models that are related as well.

The fastest way to achieve this:-
Want to delete all data from the table
Post.delete_all
Want to delete specific data from the table, then the right way to do it is
Post.where(YOUR CONDITIONS).delete_all
# this above solution is working in Rails 5.2.1, delete_all don't expect any parameter
# you can let me know if this works in different versions.
# In the older version, you might need to do something like this:-
Post.delete_all "Your Conditions"

This way worked for me, added this route below in routes.rb
get 'del_all', to: 'items#del_all' # del_all is my custom action and items is it's controller
def del_all #action in ItemsController
if Item.any?
Item.destroy_all
redirect_to items_url, notice: "Items were destroyed."
else
redirect_to items_url, notice: "No item found here."
end
end
According to documentation:
2.5 Singular Resources - Sometimes, you have a resource that clients always look up without referencing an ID. For example, you would like /profile to always show the >profile of the currently logged in user. In this case, you can use a singular >resource to map /profile (rather than /profile/:id) to the show action: get 'profile', to: 'users#show'

Related

Pass a table from controller to view - Rails

In my Rails site, I have a model named Person, which has an ActionController and migration (database). I've inserted few rows to this table using the console (and saved them there!).
In the PersonController I have a method "list" which I want to list all the people which are in the database :
def list
#persons = Person.all
end
However, in the list.html.erb file in the person's view, I can't access this arrey. Trying to write something like :
<% #persons.each do |r| %>
raises an error claims that #person is nil.
I think I'm doing something wrong here. In conclusion, how can I pass a database from the controller to the view, and how can I disply it?
Thanks
The method you are using to transfer data from the controller to the view is appropriate. My guess is that Person.all is not returning any results, meaning your database is not being populated via the console. Try adding your data in via seeds.rb in the db directory, and then run rake db:seed. That should do it for you. Also, generally lists of models are run through the 'index' route. I would recommend using that instead of a route 'list'.
You can also check this post to make sure you are using the console correctly:
how to add data to database from rails console
*****************EDIT*******************
To use index to list display a list of a model, open your routes.rb file and add the people resource to generate all routes for the person model
resources :people
That will give you index, show, edit, create, update, and destroy routes (run rake routes to see a list of all the routes). If you do not want all of those, you can use only: and except: with the resource command to limit the routes created. Example
resources :people, only: index
You then need to update your controller to match each route that you want to use. So instead of 'list' you can use index, show, edit, update, create, and destroy.
def index
#people = Person.all
end
is an example of the index action definition. Then you just need a view to match the action, like index.html.erb. If you have any people in the database, they should now be in the #people variable during the index action and you can use that to list out each person. If you want to create some people to try it out, you can use the console, the show action you created using the resources command in the routes.rb, or use the seed.rb file and run rake db:seed.
Your variable in controller is #persons and not #person. The error you are getting is #person is nil. If that is not the problem, then please remember that rails uses singular for the model name, which is Person and plural in other cases, people in naming the tables and the controllers.
If this doesn't help, please post your real filenames, and your first line of the controller along with other relevant code.
Good luck!
Check the database and make sure the data is there. In addition, make sure you use Person.create and not Person.new when you are creating a record via the console.
Person.new must be assigned to a variable and save must be called on that variable. Create doesn't require that extra step
u = User.new(:first => "Chris", :last => "Tilley")
u.save! //required with new
u = Person.create(:first => "Chris", :last => "Tilley") //doesn't require save

How to fetch a random record in rails?

I am trying to fetch a random record in rails, to render in my home page.
I have a post model with content and title attributes. Lets say i wanted to fetch a random post(content and title) for some reason, How can i go about it in ruby. Thanks in advance.
You might find this gem handy : Faker
It allows to generate random strings with some meaning.
For example, a name :
Faker::Name.name => “Bob Hope”
Or an e-mail
Faker::Internet.email
In addition to this gem, if you want to be able to generate mock models very easily, I recommend the gem Factory Girl
It allows you to create factories for your model, sou you can generate a model with random attributes quickly.
Posting another answer since the first one answered to an unclear question.
As #m_x said, you can use RANDOM() for SQL.
If you don't mind loading all the dataset, you can do it in ruby as well :
Post.all.sample
This will select one random record from all Posts.
I know this is an old question, but since no answer was chosen, answering it might be helpful for other users.
I think the best way to go would be generating a random offset in Ruby and using it in your Active Record statement, like so:
Thing.limit(1).offset(rand(Thing.count)).first
This solution is also performant and portable.
In your post controller,
def create
#post = Post.new(params[:post])
if you_want_some_random_title_and_content
title_length = 80 #choose your own
content_length = 140 #choose your own
#post.title = (0...title_length).map{(65+rand(26)).chr}.join
#post.content = (0...content_length).map{(65+rand(26)).chr}.join
end
if #post.save
redirect_to #post
else
render 'new'
end
end
Using Kent Fedric's way to generate random string
unfortunately, there is no database-agnostic method for fetching a random record, so ActiveRecord does not implement any.
For postgresql you can use :
Post.order( 'RANDOM()' ).first
To fetch one random post.
Additionnally, i usually create a scope for this:
class Post < ActiveRecord::Base
scope :random_order, ->{ order 'RANDOM()' }
end
so if you change your RDBMS, you just have to change the scope.

Create Rails model with argument of associated model?

I have two models, User and PushupReminder, and a method create_a_reminder in my PushupReminder controller (is that the best place to put it?) that I want to have create a new instance of a PushupReminder for a given user when I pass it a user ID. I have the association via the user_id column working correctly in my PushupReminder table and I've tested that I can both create reminders & send the reminder email correctly via the Rails console.
Here is a snippet of the model code:
class User < ActiveRecord::Base
has_many :pushup_reminders
end
class PushupReminder < ActiveRecord::Base
belongs_to :user
end
And the create_a_reminder method:
def create_a_reminder(user)
#user = User.find(user)
#reminder = PushupReminder.create(:user_id => #user.id, :completed => false, :num_pushups => #user.pushups_per_reminder, :when_sent => Time.now)
PushupReminderMailer.reminder_email(#user).deliver
end
I'm at a loss for how to run that create_a_reminder method in my code for a given user (eventually will be in a cron job for all my users). If someone could help me get my thinking on the right track, I'd really appreciate it.
Thanks!
Edit: I've posted a sample Rails app here demonstrating the stuff I'm talking about in my answer. I've also posted a new commit, complete with comments that demonstrates how to handle pushup reminders when they're also available in a non-nested fashion.
Paul's on the right track, for sure. You'll want this create functionality in two places, the second being important if you want to run this as a cron job.
In your PushupRemindersController, as a nested resource for a User; for the sake of creating pushup reminders via the web.
In a rake task, which will be run as a cron job.
Most of the code you need is already provided for you by Rails, and most of it you've already got set in your ActiveRecord associations. For #1, in routes.rb, setup nested routes...
# Creates routes like...
# /users/<user_id>/pushup_reminders
# /users/<user_id>/pushup_reminders/new
# /users/<user_id>/pushup_reminders/<id>
resources :users do
resources :pushup_reminders
end
And your PushupRemindersController should look something like...
class PushupRemindersController < ApplicationController
before_filter :get_user
# Most of this you'll already have.
def index
#pushup_reminders = #user.pushup_reminders
respond_with #pushup_reminders
end
# This is the important one.
def create
attrs = {
:completed => false,
:num_pushups => #user.pushups_per_reminder,
:when_sent => Time.now
}
#pushup_reminder = #user.pushup_reminders.create(attrs)
respond_with #pushup_reminder
end
# This will handle getting the user from the params, thanks to the `before_filter`.
def get_user
#user = User.find(params[:user_id])
end
end
Of course, you'll have a new action that will present a web form to a user, etc. etc.
For the second use case, the cron task, set it up as a Rake task in your lib/tasks directory of your project. This gives you free reign to setup an action that gets hit whenever you need, via a cron task. You'll have full access to all your Rails models and so forth, just like a controller action. The real trick is this: if you've got crazy custom logic for setting up reminders, move it to an action in the PushupReminder model. That way you can fire off a creation method from a rake task, and one from the controller, and you don't have to repeat writing any of your creation logic. Remember, don't repeat yourself (DRY)!
One gem I've found quite useful in setting up cron tasks is the whenever gem. Write your site-specific cron jobs in Ruby, and get the exact output of what you'd need to paste into a cron tab (and if you're deploying via Capistrano, total hands-off management of cron jobs)!
Try setting your attr_accessible to :user instead of :user_id.
attr_accessible :user
An even better way to do this however would be to do
#user.pushup_reminders.create
That way the user_id is automatically assigned.
Use nested routes like this:
:resources :users do
:resources :pushup_reminders
end
This will give you params[:user_id] & params[:id] so you can find your objects in the db.
If you know your user via sessions, you won't need to nest your routes and can use that to save things instead.
Using restful routes, I would recommend using the create action in the pushup_reminders controller. This would be the most conventional and Restful way to do this kind of object creation.
def create
#user = User.find(params[:user_id]
#reminder = #user.pushup_reminders.create()
end
If you need to check whether object creation was successful, try using .new and .save

rails auditor gem - audits.user_id may not be NULL

I'm using the auditor gem to track changes in my models, and I find it quite annoying that whenever I'm trying to work from console I get this error (I guess user_id is taken from current_user and it's not associated).
I'm trying to create some objects for development, and just have to do it from the dbconsole every time..
I use 'audit(:create, :update, :destroy)' and not 'audit!'.
Does anyone knows if I can suppress these errors or disable the user_id null check? (I don't care that if in production I run console and create an object, I'll have a NULL there).
Many thanks,
Zach
I had the same issue. Problem was that I didn't have any attr_accessible declared. Read this: https://github.com/collectiveidea/audited#gotchas
edit:
Also, I had to define a method for current_user:
def current_user
User.find_by_username 'root'
end
Why don't you just set current_user to a user object before your audit work?
current_user = User.first
...your other code here

Can I make Rails update_attributes with nested form find existing records and add to collections instead of creating new ones?

Scenario: I have a has_many association (Post has many Authors), and I have a nested Post form to accept attributes for Authors.
What I found is that when I call post.update_attributes(params[:post]) where params[:post] is a hash with post and all author attributes to add, there doesn't seem to be a way to ask Rails to only create Authors if certain criteria is met, e.g. the username for the Author already exists. What Rails would do is just failing and rollback update_attributes routine if username has uniqueness validation in the model. If not, then Rails would add a new record Author if one that does not have an id is in the hash.
Now my code for the update action in the Post controller becomes this:
def update
#post = Post.find(params[:id])
# custom code to work around by inspecting the author attributes
# and pre-inserting the association of existing authors into the testrun's author
# collection
params[:post][:authors_attributes].values.each do |author_attribute|
if author_attribute[:id].nil? and author_attribute[:username].present?
existing_author = Author.find_by_username(author_attribute[:username])
if existing_author.present?
author_attribute[:id] = existing_author.id
#testrun.authors << existing_author
end
end
end
if #post.update_attributes(params[:post])
flash[:success] = 'great!'
else
flash[:error] = 'Urgg!'
end
redirect_to ...
end
Are there better ways to handle this that I missed?
EDIT: Thanks for #Robd'Apice who lead me to look into overriding the default authors_attributes= function that accepts_nested_attributes_for inserts into the model on my behalf, I was able to come up with something that is better:
def authors_attributes=(authors_attributes)
authors_attributes.values.each do |author_attributes|
if author_attributes[:id].nil? and author_attributes[:username].present?
author = Radar.find_by_username(radar_attributes[:username])
if author.present?
author_attributes[:id] = author.id
self.authors << author
end
end
end
assign_nested_attributes_for_collection_association(:authors, authors_attributes, mass_assignment_options)
end
But I'm not completely satisfied with it, for one, I'm still mucking the attribute hashes from the caller directly which requires understanding of how the logic works for these hashes (:id set or not set, for instance), and two, I'm calling a function that is not trivial to fit here. It would be nice if there are ways to tell 'accepts_nested_attributes_for' to only create new record when certain condition is not met. The one-to-one association has a :update_only flag that does something similar but this is lacking for one-to-many relationship.
Are there better solutions out there?
This kind of logic probably belongs in your model, not your controller. I'd consider re-writing the author_attributes= method that is created by default for your association.
def authors_attributes=(authors_attributes)
authors_attributes.values.each do |author_attributes|
author_to_update = Author.find_by_id(author_attributes[:id]) || Author.find_by_username(author_attributes[:username]) || self.authors.build
author_to_update.update_attributes(author_attributes)
end
end
I haven't tested that code, but I think that should work.
EDIT: To retain the other functionality of accepts_nested_Attributes_for, you could use super:
def authors_attributes=(authors_attributes)
authors_attributes.each do |key, author_attributes|
authors_attributes[key][:id] = Author.find_by_username(author_attributes[:username]).id if author_attributes[:username] && !author_attributes[:username].present?
end
super(authors_attributes)
end
If that implementation with super doesn't work, you probably have two options: continue with the 'processing' of the attributes hash in the controller (but turn it into a private method of your controller to clean it up a bit), or continue with my first solution by adding in the functionality you've lost from :destroy => true and reject_if with your own code (which wouldn't be too hard to do). I'd probably go with the first option.
I'd suggest using a form object instead of trying to get accepts_nested_attributes to work. I find that form object are often much cleaner and much more flexible. Check out this railscast

Resources