Keva161
Keva161

Reputation: 2683

How to automaticly assigned a entry a unique id for use in a relationship?

A basic overview of my app. There is currently two models. A jobs model and a clients model. Both models have a has_and_belongs_to_many relationship as I intended to allow the user to create a client entry and then assign them one or many jobs.

Here are both of my models.

Clients -

class Client < ActiveRecord::Base 
  has_and_belongs_to_many :job
end

Jobs -

class Job < ActiveRecord::Base
  has_and_belongs_to_many :client
end

I have been doing some research and I think im right in thinking that the relationship needs a foreign key to function so have added a client_id column & a job_id column to my database.

The clients page is currently working and here is my controller for that.

class ClientsController < ApplicationController

        def index
          @clients = Client.all

          respond_to do |format|
            format.html # index.html.erb
            format.json { render json: @clients }
          end
        end

        # GET /Clients/1
        # GET /Clients/1.json
        def show
          @clients = Client.find(params[:id])

          respond_to do |format|
            format.html # show.html.erb
            format.json { render json: @clients }
          end
        end

        # GET /Clients/new
        # GET /Clients/new.json
        def new
          @clients = Client.new

          respond_to do |format|
            format.html # new.html.erb
            format.json { render json: @clients }
          end
        end

        # GET /Clients/1/edit
        def edit
          @clients = Client.find(params[:id])
        end


        def create
          @clients = Client.new(params[:client])

          respond_to do |format|
            if @clients.save
              format.html { redirect_to @clients, notice: 'Client was successfully created.' }
              format.json { render json: @clients, status: :created, location: @clients }
            else
              format.html { render action: "new" }
              format.json { render json: @clients.errors, status: :unprocessable_entity }
            end
          end
        end

        # PUT /Clients/1
        # PUT /Clients/1.json
        def update
          @clients = Client.find(params[:id])

          respond_to do |format|
            if @clients.update_attributes(params[:client])
              format.html { redirect_to @clients, notice: 'Client was successfully updated.' }
              format.json { head :no_content }
            else
              format.html { render action: "edit" }
              format.json { render json: @clients.errors, status: :unprocessable_entity }
            end
          end
        end

        # DELETE /Clients/1
        # DELETE /Clients/1.json
        def destroy
          @clients = Client.find(params[:id])
          @clients.destroy

          respond_to do |format|
            format.html { redirect_to :clients , notice: 'Client was successfully removed.'}
            format.json { head :no_content }
          end
        end

        def details
            @clients = Client.find_by_id(params[:id])
            @jobs = Client.job
        end
      end

And here's what I currently have for my jobs controller.

class JobsController < ApplicationController

  def index
    @jobs = Job.find(:all)

    respond_to do |format|
      format.html # index.html.erb
      format.xml { render :xml => @job }
    end
  end

  def new
    @jobs = Job.new 

    respond_to do |format|
      format.html # index.html.erb
      format.xml { render :xml => @job }
    end
  end

  def create
    @jobs = Job.new(params[:job])
    @cients = Client.find = Client.find(params[:id])

    respond_to do |format|
      if @jobs.save
        format.html { redirect_to(@jobs,
                      :notice => 'Job was successfully created.') }
        format.xml  { render :xml => @jobs,
                      :status => :created, :location => @Job }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @jobs.errors,
                      :status => :unprocessable_entity }
      end
    end
  end
end

In my jobs form I was given thr following code which added a drop down with all the created clients.

<%= select("job", "client_id", Client.all.collect {|c| [ c.name, c.id ] }, {:include_blank => 'None'})%> 

When I press save though. I recieve the following error.

unknown attribute: client_id

Application Trace | Framework Trace | Full Trace
app/controllers/jobs_controller.rb:22:in `new'
app/controllers/jobs_controller.rb:22:in `create'

I assume this is because I need to define a way of finding the client_id in my job creation as well as specifying one in my client creation.

This is my first rails app though so im not quite sure how.

Any help would be greatly appreciated.

Upvotes: 0

Views: 198

Answers (2)

user229044
user229044

Reputation: 239240

Your jobs table doesn't have a client_id, nor should it. You need to create a junction table to facilitate a many-to-many relationship. It should be called clients_jobs and contain an integer client_id and job_id.

There is a lot more wrong here. Here are just the things I caught at a casual glance:

  1. This line:

    @cients = Client.find = Client.find(params[:id])
    

    should be:

    @cients = Client.find(params[:id])
    
  2. Pluralization is important in Rails. A client doesn't have many "job". It has many jobs. Your models should reflect this:

    class Client < ActiveRecord::Base 
      has_and_belongs_to_many :jobs
    end
    
    class Job < ActiveRecord::Base
      has_and_belongs_to_many :clients
    end
    
  3. You'll need to create a junction table via a migration, which is where your foreign keys will exist:

    $ rails g migration AddClientsJobsTable 
    
  4. In index and new, you first create @jobs = Job.new and then you render it via :xml => @job. Again, pluralization is important. You need @job = Job.new. You have the same problem in create, except you've dropped the 's' and capitalized the 'J': :location => @Job } You can't do that in programming. Case and spelling both matter.

  5. Job.find(:all) or Client.all: Pick one. Don't mix find :all and .all.

  6. @clients = Client.find(params[:id]). You're finding a single specific Client, not a collection of clients. Your variable should be called @client. This is not an error, but it is seriously ugly.

Upvotes: 1

TheIrishGuy
TheIrishGuy

Reputation: 2573

pluralize your jobs and clients in your associations. I.E

has_many_and_belongs_to :jobs
has_many_and_belongs_to :clients

And if you do not use the alternative to this many-to-many associations with the ActiveRecord :through method (the alternative to HMABT) You must create the join table yourself which is a table of job_id's and client_id's.

Upvotes: 1

Related Questions