Search code examples
ruby-on-railsroutescontrollersself-join

rails self join


I want a user to be able to create a challenge (challenges_created) and other users to be able to offer support to achieve them (challenges_supported). I tried to do this with a self joined challenge model with its resources nested beneath the users resource. I currently have models:

class User < ActiveRecord::Base
  attr_accessible :name, :supporter_id, :challenger_id

  has_many :challenges_created, :class_name => 'Challenge', :foreign_key => :challenger_id
  has_many :challenges_supported, :class_name => 'Challenge', :foreign_key => :supporter_id
end

and

class Challenge < ActiveRecord::Base
  attr_accessible :challenger, :completion_date, :description, :duration, :status,      :supporter, :title

  belongs_to :challenger, :class_name => 'User'
  has_many :supporters, :class_name => 'User'
end

I think that I would need full CRUD and corresponding views both for when users are creating challenges and when they are supporting them. Because of this, I created 2 controllers named challenges_created_controller and challenges_supported_controller.

My routes.rb file is:

resources :users do
  resources :challenges_created
  resources :challenges_supported
end

The problem that I am encountering with this setup is that when I try to create a new challenge at

http://localhost:3000/users/3/challenges_created/new 

I receive the message

Showing /home/james/Code/Rails/test_models/app/views/challenges_created/_form.html.erb where line #1 raised:

undefined method `user_challenges_path' for #<#    <Class:0x007fb154de09d8>:0x007fb1500c0f90>
Extracted source (around line #1):

1: <%= form_for [@user, @challenge] do |f| %>
2:   <% if @challenge.errors.any? %>

The result is the same for the edit action too. I have tried many things but if I were to reference @challenge_created in the form_for then it is not matching the Challenge model.

Can anybody please advise on how what I am doing wrong. Thank you in advance. My schema is:

  create_table "users", :force => true do |t|
    t.string   "name"
    t.datetime "created_at",    :null => false
    t.datetime "updated_at",    :null => false
    t.integer  "challenger_id"
    t.integer  "supporter_id"
  end

  create_table "challenges", :force => true do |t|
    t.string   "title"
    t.text     "description"
    t.integer  "duration"
    t.date     "completion_date"
    t.string   "status"
    t.datetime "created_at",      :null => false
    t.datetime "updated_at",      :null => false
    t.integer  "challenger_id"
    t.integer  "supporter_id"
  end

Solution

  • I think the problem is that you have a challenge_created controller, but you do not have model for it. In you form you specify a user and a challenge so rails tries to find a controller for challenge, not challenge_created. Rails thinks that for a model you have a controller named based on the convention.

    I recommend you not to create two different controllers for challenges. Use only one and differenciate on actions. E.g. ou can create a list_created and list_supported action in challenges.