1
votes

I have 2 versions of an same index page which display a list of products. Regular view - Displays List Admin view - Displays List with options to edit, delete etc.

The index action just makes the database query and returns that instance variable. Currently, I have the same index action for rendering the index page. I want to reuse the index action form product into the admin controller.

def index
    @products = Product.all
end

routes:

/product/index  => product#index

/admin/product/index  => product#index

I tried the prepend_view_path technique given [here | How can I intercept rails's template rendering, but then this always ends up rendering the admin/product/index.html.erb file in both cases.

I want the Product#index controller#action to render:

/index.html.erb for /product/index

and

/admin/product/index.html.erb for /admin/product/index

Can someone help me with how this could be done in an elegant way instead of just writing the same action for admin controller class and product controller class.

PS: I'm just one week into ruby and ruby on rails. Any help is much appreciated.

3

3 Answers

2
votes

There is a Mistake in routes .

/product/index => product#index

/admin/product/index => product#index

Both pointing to the same contoller names as product.

I would suggest these routes

resources  :admin do 
  resources :product do 
  end
end

resources :product do 
end

By doing so you make sure that you have two products Controller. One with Admin::ProductController Second ProductController

admin_product_path for admin view product_path for normal view

1
votes

From within your controllers, just render view you want to serve for user, I mean:

ProductsController
def index
  # ...
  render 'index'
end

Admin::ProductsController
def index
  # ...
  render 'products/index'
end
0
votes

I faced this challenge when working on a Rails 6 application.

I had two types of users: Customers and Admins. I was using the Devise gem for authentication. I wanted the Products views for the Customer to be different from the Admins View.

I already had an app/controllers/admins directory in the controllers for the Devise configuration for Admins.

Here's how I did it:

First, define a new route for the Admins products view using the admins namespace.

namespace :admins do
  resources :products do
  end
end

Note: This will affect the Paths/URLs for the Admins. Say, the products_path will not be admins_products_path.

Then, in the controllers add the products_controller.rb to the app/controllers/admins directory:

class Admins::ProductsController < ApplicationController
  before_action :set_product, only: [:show, :edit, :update, :destroy]

  # GET /products
  # GET /products.json
  def index
    @products = Product.all
  end

  # GET /products/1
  # GET /products/1.json
  def show
  end

  # GET /products/new
  def new
    @product = Product.new
  end

  # GET /products/1/edit
  def edit
  end

  # POST /products
  # POST /products.json
  def create
    @product = Product.new(product_params)

    respond_to do |format|
      if @product.save
        format.html { redirect_to admins_product_path(@product), notice: 'Product was successfully created.' }
        format.json { render :show, status: :created, location: admins_product_path(@product) }
      else
        format.html { render :new }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /products/1
  # PATCH/PUT /products/1.json
  def update
    respond_to do |format|
      if @product.update(product_params)
        format.html { redirect_to admins_product_path(@product), notice: 'Product was successfully updated.' }
        format.json { render :show, status: :ok, location: admins_product_path(@product) }
      else
        format.html { render :edit }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /products/1
  # DELETE /products/1.json
  def destroy
    @product.destroy
    respond_to do |format|
      format.html { redirect_to admins_products_url, notice: 'Product was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_product
      @product = Product.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def product_params
      params.require(:product).permit(:name, :sku, :short_description, :full_description)
    end
end

Note: Take note of the ProductsController namespacing using the Admins Module and the modified paths in the create, update and destroy actions od the

And finally, in the views, add the views associated with the Admins Products in the app/views/admins/products directory.

Note: You may have to modify the paths in the views to correspond with the routes for the admins products. Say, the show view for admins products will be admins_product_path(product) and not product or product_path(product).

There is a cleaner approach using the cells gem. This eliminates the need to duplicate code, and it comes in handy when you need to define views for up to 3 or more roles. You can read up more about how to use it here: Object-Oriented Views in Rails.

That's all.

I hope this helps