Skip to content

Commit

Permalink
Add context to Page
Browse files Browse the repository at this point in the history
  • Loading branch information
goosys committed Nov 14, 2023
1 parent 21c5288 commit 793187e
Show file tree
Hide file tree
Showing 17 changed files with 255 additions and 36 deletions.
46 changes: 38 additions & 8 deletions app/controllers/administrate/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ class ApplicationController < ActionController::Base
def index
authorize_resource(resource_class)
search_term = params[:search].to_s.strip
resources = filter_resources(scoped_resource, search_term: search_term)
authorized_scope = authorize_scope(scoped_resource)
resources = filter_resources(authorized_scope, search_term: search_term)
resources = apply_collection_includes(resources)
resources = order.apply(resources)
resources = paginate_resources(resources)
page = Administrate::Page::Collection.new(dashboard, order: order)
page.context = self

render locals: {
resources: resources,
Expand All @@ -20,22 +22,28 @@ def index
end

def show
page = Administrate::Page::Show.new(dashboard, requested_resource)
page.context = self
render locals: {
page: Administrate::Page::Show.new(dashboard, requested_resource),
page: page,
}
end

def new
resource = new_resource
authorize_resource(resource)
page = Administrate::Page::Form.new(dashboard, resource)
page.context = self
render locals: {
page: Administrate::Page::Form.new(dashboard, resource),
page: page,
}
end

def edit
page = Administrate::Page::Form.new(dashboard, requested_resource)
page.context = self
render locals: {
page: Administrate::Page::Form.new(dashboard, requested_resource),
page: page,
}
end

Expand All @@ -49,8 +57,10 @@ def create
notice: translate_with_resource("create.success"),
)
else
page = Administrate::Page::Form.new(dashboard, resource)
page.context = self
render :new, locals: {
page: Administrate::Page::Form.new(dashboard, resource),
page: page,
}, status: :unprocessable_entity
end
end
Expand All @@ -62,8 +72,9 @@ def update
notice: translate_with_resource("update.success"),
)
else
page = Administrate::Page::Form.new(dashboard, requested_resource)
render :edit, locals: {
page: Administrate::Page::Form.new(dashboard, requested_resource),
page: page,
}, status: :unprocessable_entity
end
end
Expand Down Expand Up @@ -186,7 +197,11 @@ def requested_resource
end

def find_resource(param)
scoped_resource.find(param)
authorize_scope(scoped_resource).find(param)
end

def authorize_scope(scope)
scope
end

def scoped_resource
Expand All @@ -201,7 +216,7 @@ def apply_collection_includes(relation)

def resource_params
params.require(resource_class.model_name.param_key).
permit(dashboard.permitted_attributes(action_name)).
permit(dashboard.permitted_attributes(action_name, self)).
transform_values { |v| read_param_value(v) }
end

Expand Down Expand Up @@ -273,6 +288,8 @@ def new_resource(params = {})
helper_method :new_resource

def authorize_resource(resource)
contextualize_resource(resource) if resource.is_a?(ActiveRecord::Base)

if authorized_action?(resource, action_name)
resource
else
Expand All @@ -283,6 +300,19 @@ def authorize_resource(resource)
end
end

def authorized_new_resource
new_resource.tap do |resource|
authorize_resource(resource)
end
end
helper_method :authorized_new_resource

# Override this if you want to contextualize the resource differently.
#
# @param resource [ActiveRecord::Base] A resource to be contextualized.
# @return nothing
def contextualize_resource(resource); end

def paginate_resources(resources)
resources.page(params[:_page]).per(records_per_page)
end
Expand Down
6 changes: 4 additions & 2 deletions app/controllers/concerns/administrate/punditize.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ def policy_namespace
[]
end

def scoped_resource
namespaced_scope = policy_namespace + [super]
def authorize_scope(scope)
namespaced_scope = policy_namespace + [scope]
policy_scope!(pundit_user, namespaced_scope)
end

def authorize_resource(resource)
contextualize_resource(resource) if resource.is_a?(ActiveRecord::Base)

namespaced_resource = policy_namespace + [resource]
authorize namespaced_resource
end
Expand Down
11 changes: 11 additions & 0 deletions docs/customizing_controller_actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ class Admin::FoosController < Admin::ApplicationController
# resource_class.with_less_stuff
# end
# end


# Override this if you want to contextualize the resource differently.
# This will be used to contextualize the resource for the all actions without `index`.
#
# def contextualize_resource(resource)
# case action_name
# when "new", "create"
# resource.author = current_user
# end
# end
end
```

Expand Down
6 changes: 3 additions & 3 deletions lib/administrate/base_dashboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def all_attributes
attribute_types.keys
end

def form_attributes(action = nil)
def form_attributes(action = nil, _context = nil)
action =
case action
when "update" then "edit"
Expand All @@ -68,8 +68,8 @@ def specific_form_attributes_for(action)
self.class.const_get(cname) if self.class.const_defined?(cname)
end

def permitted_attributes(action = nil)
form_attributes(action).map do |attr|
def permitted_attributes(action = nil, context = nil)
form_attributes(action, context).map do |attr|
attribute_types[attr].permitted_attribute(
attr,
resource_class: self.class.model,
Expand Down
7 changes: 6 additions & 1 deletion lib/administrate/field/belongs_to.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ def include_blank_option
private

def candidate_resources
scope = options[:scope] ? options[:scope].call : associated_class.all
scope =
if options[:scope]
options[:scope].call(self)
else
associated_class.all
end

order = options.delete(:order)
order ? scope.reorder(order) : scope
Expand Down
2 changes: 2 additions & 0 deletions lib/administrate/page/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ def item_associations
dashboard.try(:item_associations) || []
end

attr_accessor :context

private

def attribute_field(dashboard, resource, attribute_name, page)
Expand Down
2 changes: 1 addition & 1 deletion lib/administrate/page/form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize(dashboard, resource)
attr_reader :resource

def attributes(action = nil)
dashboard.form_attributes(action).map do |attribute|
dashboard.form_attributes(action, context).map do |attribute|
attribute_field(dashboard, resource, attribute, :form)
end
end
Expand Down
24 changes: 20 additions & 4 deletions spec/controllers/admin/customers_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
describe Admin::CustomersController, type: :controller do
describe "GET index" do
it "passes all customers to the view" do
customer = create(:customer)
customers = create_list(:customer, 5)

locals = capture_view_locals { get :index }
expect(locals[:resources]).to eq([customer])
expect(locals[:resources]).to eq(customers)
end

it "applies any scope overrides" do
Expand Down Expand Up @@ -47,6 +47,22 @@
expect(locals[:resources].map(&:id)).to eq customers.map(&:id).sort
end

context "when the user is an admin" do
controller(Admin::CustomersController) do
def authenticate_admin
@current_user = Customer.last
end
end

it "passes one customers to the view" do
_other_customers = create_list(:customer, 5)
customer = create(:customer)

locals = capture_view_locals { get :index }
expect(locals[:resources]).to eq([customer])
end
end

context "with alternate sorting attributes" do
controller(Admin::CustomersController) do
def default_sorting_attribute
Expand Down Expand Up @@ -107,9 +123,9 @@ def default_sorting_direction
describe "POST create" do
describe "with valid params" do
it "creates a new Customer" do
expect {
expect do
post :create, params: { customer: attributes_for(:customer) }
}.to change(Customer, :count).by(1)
end.to change(Customer, :count).by(1)
end

it "redirects to the created customer" do
Expand Down
68 changes: 64 additions & 4 deletions spec/controllers/admin/orders_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ def pundit_user
end

describe "GET new" do
it "raises a Pundit error" do
expect { get :new }.to raise_error(Pundit::NotAuthorizedError)
it "allows me to new my records" do
expect { get :new }.not_to raise_error
end
end

Expand Down Expand Up @@ -153,8 +153,8 @@ def pundit_user
end

describe "GET new" do
it "raises a Pundit error" do
expect { get :new }.to raise_error(Pundit::NotAuthorizedError)
it "allows me to new my records" do
expect { get :new }.not_to raise_error
end
end

Expand Down Expand Up @@ -232,5 +232,65 @@ def send_request(order:)
expect(controller.send(:authorized_action?, o, :destroy)).to be false
end
end

context "when the user is an admin" do
controller(Admin::OrdersController) do
def pundit_user
Customer.find_by(name: "Current User")
end
end

let!(:user) { create(:customer, name: "Current User") }

describe "GET new" do
it "allows me to new my records" do
expect { get :new }.not_to raise_error
end
end

describe "POST create" do
def send_request
post(
:create,
params: {
order: attributes_for(:order, customer: nil),
},
)
end

it "allows me to create my records" do
send_request
expect(response).to redirect_to([:admin, (order = Order.last)])
expect(order.customer).to eq(user)
end
end
end
end

context "when the user is not an admin" do
let!(:user) { create(:customer, name: "Target User") }

describe "GET new" do
it "allows me to new records" do
expect { get :new }.not_to raise_error
end
end

describe "POST create" do
def send_request
post(
:create,
params: {
order: attributes_for(:order, customer: nil, customer_id: user.id),
},
)
end

it "allows me to create my records with target customer" do
send_request
expect(response).to redirect_to([:admin, (order = Order.last)])
expect(order.customer).to eq(user)
end
end
end
end
Loading

0 comments on commit 793187e

Please sign in to comment.