Skip to content

Commit

Permalink
adding destroy config section and support for custom destroy methods …
Browse files Browse the repository at this point in the history
…on models
  • Loading branch information
snmgian committed Mar 17, 2011
1 parent a8f20fa commit fa48e16
Show file tree
Hide file tree
Showing 13 changed files with 243 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -20,3 +20,4 @@ spec/dummy_app/log/*.log
tmp/**/*
/.emacs.desktop
.idea/*.xml
*~
15 changes: 15 additions & 0 deletions README.mkd
Expand Up @@ -809,6 +809,21 @@ accomplished like this:
end
end

**Soft destroys**

When the admin interface deletes an object it invokes the destroy method on the object. But if another method must be invoked instead of destroy one can assign a configuration to achieve that:


RailsAdmin.config do |config|
config.model Team do
destroy do
soft_destroy :custom_destroy
end
end
end

If the soft_destroy configuration receives `true` instead of a `:symbol`, the method soft_destroy will be invoked by default.

Authorization
-------------

Expand Down
58 changes: 56 additions & 2 deletions app/controllers/rails_admin/main_controller.rb
Expand Up @@ -120,7 +120,7 @@ def delete
def destroy
@authorization_adapter.authorize(:destroy, @abstract_model, @object) if @authorization_adapter

@object = @object.destroy
@object = destroy_object
flash[:notice] = t("admin.delete.flash_confirmation", :name => @model_config.list.label)

AbstractHistory.create_history_item("Destroyed #{@model_config.list.with(:object => @object).object_label}", @object, @abstract_model, _current_user)
Expand All @@ -141,7 +141,7 @@ def bulk_destroy
@authorization_adapter.authorize(:bulk_destroy, @abstract_model) if @authorization_adapter

scope = @authorization_adapter && @authorization_adapter.query(params[:action].to_sym, @abstract_model)
@destroyed_objects = @abstract_model.destroy(params[:bulk_ids], scope)
@destroyed_objects = bulk_destroy_objects(params[:bulk_ids], scope)

@destroyed_objects.each do |object|
message = "Destroyed #{@model_config.list.with(:object => object).object_label}"
Expand All @@ -165,6 +165,38 @@ def handle_error(e)

private

# Destroy an object selecting the destroy strategy
def destroy_object
soft_destroy_method = get_soft_destroy_method

if soft_destroy_method
@object.send soft_destroy_method
else
@object.destroy
end
end

# Destroy bulk objects selecting the destroy strategy
def bulk_destroy_objects bulk_ids, scope
soft_destroy_method = get_soft_destroy_method

if soft_destroy_method
@destroyed_objects = bulk_soft_destroy(scope, bulk_ids, soft_destroy_method)
else
@destroyed_objects = @abstract_model.destroy(bulk_ids, scope)
end
end

# Performs a soft_destroy on the objects whose IDs are present in the bulk_ids array
def bulk_soft_destroy scope, bulk_ids, soft_destroy_method
scope ||= @abstract_model.model
scope = scope.where(:id => bulk_ids)
scope.to_a.each do |object|
object.send soft_destroy_method
end
end


def get_bulk_objects
scope = @authorization_adapter && @authorization_adapter.query(params[:action].to_sym, @abstract_model)
@bulk_ids = params[:bulk_ids]
Expand Down Expand Up @@ -239,6 +271,28 @@ def get_attributes
end
end

# If soft_destroy is configured as a Symbol it invokes a method with that name
# If soft_destory is not a Symbol it invokes soft_destroy method
# Else invokes destroy method
def get_soft_destroy_method
soft_destroy = @model_config.destroy.soft_destroy

method = nil
if Symbol === soft_destroy
method = soft_destroy

elsif soft_destroy
method = :soft_destroy
end

if method
return method if @abstract_model.model.instance_methods.include? method
raise NoMethodError.new("#{@object} has no method #{soft_destroy}")
else
return nil
end
end

def redirect_to_on_success
param = @abstract_model.to_param
pretty_name = @model_config.update.label
Expand Down
2 changes: 1 addition & 1 deletion lib/rails_admin/config/model.rb
Expand Up @@ -40,7 +40,7 @@ def edit(&block)
# store the configurations.
def method_missing(m, *args, &block)
responded_to = false
[:create, :list, :navigation, :update].each do |s|
[:create, :destroy, :list, :navigation, :update].each do |s|
section = send(s)
if section.respond_to?(m)
responded_to = true
Expand Down
1 change: 1 addition & 0 deletions lib/rails_admin/config/sections.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/string/inflections'
require 'rails_admin/config/sections/create'
require 'rails_admin/config/sections/destroy'
require 'rails_admin/config/sections/list'
require 'rails_admin/config/sections/navigation'
require 'rails_admin/config/sections/update'
Expand Down
16 changes: 16 additions & 0 deletions lib/rails_admin/config/sections/destroy.rb
@@ -0,0 +1,16 @@
require 'rails_admin/config/base'

module RailsAdmin
module Config
module Sections
# Configuration of the destroy view
class Destroy < RailsAdmin::Config::Base

# Defines if the objects will be destroyed using a custom_method
register_instance_option(:soft_destroy) do
false
end
end
end
end
end
12 changes: 12 additions & 0 deletions spec/dummy_app/app/models/club.rb
@@ -0,0 +1,12 @@
class Club < ActiveRecord::Base
validates_presence_of(:name)

def custom_destroy
update_attribute(:disabled, true)

@destroyed = true
freeze
end
end


11 changes: 11 additions & 0 deletions spec/dummy_app/app/models/coach.rb
@@ -0,0 +1,11 @@
class Coach < ActiveRecord::Base
validates_presence_of(:name)

def soft_destroy
update_attribute(:disabled, true)

@destroyed = true
freeze
end
end

13 changes: 13 additions & 0 deletions spec/dummy_app/config/initializers/rails_admin.rb
@@ -1,3 +1,16 @@
RailsAdmin.config do |c|
c.excluded_models << RelTest

c.model Coach do
destroy do
soft_destroy true
end
end

c.model Club do
destroy do
soft_destroy :custom_destroy
end
end

end
@@ -0,0 +1,14 @@
class CreateCoachesMigration < ActiveRecord::Migration
def self.up
create_table :coaches do |t|
t.string :name
t.boolean :disabled

t.timestamps
end
end

def self.down
drop_table :coaches
end
end
14 changes: 14 additions & 0 deletions spec/dummy_app/db/migrate/20110317161602_create_clubs_migration.rb
@@ -0,0 +1,14 @@
class CreateClubsMigration < ActiveRecord::Migration
def self.up
create_table :clubs do |t|
t.string :name
t.boolean :disabled

t.timestamps
end
end

def self.down
drop_table :clubs
end
end
Expand Up @@ -64,4 +64,56 @@
RailsAdmin::AbstractModel.new("Player").count.should == 3
end
end

describe "soft_bulk_destroy" do
before(:each) do
RailsAdmin::History.destroy_all

to_delete = []
to_delete << RailsAdmin::AbstractModel.new("Coach").create(:name => 'Coach 1')
to_delete << RailsAdmin::AbstractModel.new("Coach").create(:name => 'Coach 2')

@delete_ids = to_delete.map(&:id)
get rails_admin_bulk_delete_path(:model_name => "coach", :bulk_ids => @delete_ids)

click_button "Yes, I'm sure"
@coaches = RailsAdmin::AbstractModel.new("Coach").all
end

it "should be successful" do
response.should be_successful
end

it "should disable the objects" do
@coaches.each do |coach|
coach.disabled.should eql(true)
end
end
end

describe "soft_bulk_destroy_with_custom_method" do
before(:each) do
RailsAdmin::History.destroy_all

to_delete = []
to_delete << RailsAdmin::AbstractModel.new("Club").create(:name => 'Club 1')
to_delete << RailsAdmin::AbstractModel.new("Club").create(:name => 'Club 2')

@delete_ids = to_delete.map(&:id)
get rails_admin_bulk_delete_path(:model_name => "club", :bulk_ids => @delete_ids)

click_button "Yes, I'm sure"
@clubs = RailsAdmin::AbstractModel.new("Club").all
end

it "should be successful" do
response.should be_successful
end

it "should disable the objects" do
@clubs.each do |club|
club.disabled.should eql(true)
end
end
end
end
37 changes: 37 additions & 0 deletions spec/requests/basic/destroy/rails_admin_basic_destroy_spec.rb
Expand Up @@ -50,4 +50,41 @@
end
end

describe "soft_destroy" do
before(:each) do
@coach = RailsAdmin::AbstractModel.new("Coach").create(:name => "Coach 1")

get rails_admin_delete_path(:model_name => "coach", :id => @coach.id)

@req = click_button "Yes, I'm sure"
@coach = RailsAdmin::AbstractModel.new("Coach").first
end

it "should be successful" do
@req.should be_successful
end

it "should disable an object" do
@coach.disabled.should eql(true)
end
end

describe "soft_destroy_with_custom_method" do
before(:each) do
@club = RailsAdmin::AbstractModel.new("Club").create(:name => "Club 1")

get rails_admin_delete_path(:model_name => "club", :id => @club.id)

@req = click_button "Yes, I'm sure"
@club = RailsAdmin::AbstractModel.new("Club").first
end

it "should be successful" do
@req.should be_successful
end

it "should disable an object" do
@club.disabled.should eql(true)
end
end
end

0 comments on commit fa48e16

Please sign in to comment.