Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage both nested and not nested resources

I wonder what is a proper way to resolve the following problem.

I have two models :

Publisher and Issue. Publisher has_many issues.

I want to manage issues both from Publishers list and from Issues list.

For example :

  • on publishers list user can click link "Issues" placed near each publisher. then he goes to Issues list but filtered only for proper publisher. He can click "create new issue" and goes to form for add new issue. On this form i don't need to show him a select list to choose publisher

  • on Issues list user can click "create new issue" and go to form but this time he should choose publisher from select, which will be related to created issue.

Simply speaking i need crud action for issue alone and for publisher issue.

First I try to make a :

  resources :issues

  resources :publishers do
    resources :issues
  end

and in issue controller :

before_filter :find_issue

def find_issue
 @publisher = Publisher.find(params[:publisher_id]) if params[:publisher_id]
 @issues = @publisher ? @publisher.issues : Issue
end

but i have to make many if condition in my views and controller.

For example if issue is created from publisher , on success i want to redirect to publisher_issues_path instead of issue_path a vice versa. Same problem with all link like "back to list" and similar. So code is in my opinion not very transparent.

Now i wonder to use namespaces.

namespace :publishers,  do
  resources :issues
end

and make

# app/controllers/publishers/issues_controller.rb
module Publishers
  class IssuesController < ApplicationController
    # actions that expect a :publisher_id param
  end
end

# app/controllers/issues_controller.rb
class IssuesController < ApplicationController
  # your typical actions without any publisher handling
end

and make separate view for both controller actions.

Is there a better or cleaner way to resolve this kind of problem? I want to make my code dry as possible. Many thanks for reply.

like image 333
Karol85 Avatar asked Oct 20 '22 14:10

Karol85


1 Answers

Routes:

resources :issues
resources :publishes do
  resources :issues
end

Controller:

class IssuesController < ApplicationController
  before_filter :build_issue, only: [:new, :create]
  before_filter :load_issue,  only: [:show, :edit, :update, :destroy]

  def index
    @issues = issues.page(params[:page])
  end

  ... all other actions will have access to @issue

private
  def issues
    if params[:publisher_id].present?
      Publisher.find(params[:publisher_id]).issues
    else
      Issue
    end  
  rescue ActiveRecord::RecordNotFound
    redirect_to issues_path(alert: 'Publisher not found')
  end

  def build_issue
    @issue = issues.new(issue_params)
  end

  def load_issue
    @issue = issues.find(params[:id])
  rescue ActiveRecord::RecordNotFound
    redirect_to issues_path(alert: 'Issue not found')
  end

  def issue_params
    # whitelisted attributes goes here
  end
end

To avoid using conditions, use actions instead of full named path, i.e:

redirect_to action: :index
link_to 'Issues', {action: :index}
like image 91
Hesham Avatar answered Dec 03 '22 07:12

Hesham