1

I have two models that are nested, a Project has a name and a Budget, and a Budget has an amount and belongs to a Project.

I got a form page where I try to create both Project and Budget, so users can fill the name of their project in the same form where they choose the budget amount.

<%= simple_form_for @project do |f| %>
    <%= f.error_notification %>
    <%= simple_fields_for :budget do |ff| %>
      <%= ff.input :amount %>
    <% end %>
    <%= f.input :name %>
    <%= f.submit "Create", class: "btn" %>
  <% end %>

But I can't create both at the same time, when I test if my budget is valid, I miss the project_id it is linked to, and if I try to create my project first, I can't cause it misses its budget.

Here are my models :

 class Budget < ApplicationRecord
   belongs_to :projects
 end
 class Project < ApplicationRecord
   has_one :budget
   accepts_nested_attributes_for :budget
 end

Here are my migrations

class CreateBudgets < ActiveRecord::Migration[5.1]
  def change
    create_table :budgets do |t|

      t.timestamps
    end
  end
end
class CreateProjects < ActiveRecord::Migration[5.1]
  def change
    create_table :projects do |t|
      t.references :budget, foreign_key: true
      t.string :name

      t.timestamps
    end
  end
end

Finaly here is my controller for project def new @project = Project.new @project.id = 0 @budget = Budget.new puts "new in projectcontroler" end

def create
  puts "create in projectcontroler"
  # Getting filled objects from form
  @project = Project.new(project_params)
  @budget = Budget.new(budget_params)
  puts "We're on project controller"
  p @budget

  respond_to do |format|
    unless @budget.nil? 
      @project.budget = @budget

      if @project.valid?
        puts "All good now"
        @budget.save
        @project.save
        puts "Campaign successfuly created"
        format.html { redirect_to projects_path, notice: 'Success' }
      else
        puts "Unable to create campaign"
        format.html { render :new, notice: 'Project went wrong' }
      end

     else # If budget isn't saved
      puts "Unable to create budget"
      @budget.errors.full_messages.each do |mes|
        puts mes
      end
      format.html { render :new }
      format.json { render json: @budget.errors, status: :unprocessable_entity }
    end
  end
end

For now I got this issue : ActiveModel::MissingAttributeError - can't write unknown attribute project_id

I need to understand if I need to have a controller or routes for budget model, can't I create both models in this same controller ?

EDIT : Updated code

EDIT 2 : I add migrations as I think it's part of the problem

class CreateProjects < ActiveRecord::Migration[5.1]
  def change
    create_table :projects do |t|
      t.references :budget, foreign_key: true
      t.string :name
      t.timestamps
    end
  end
end
class CreateBudgets < ActiveRecord::Migration[5.1]
  def change
    create_table :budgets do |t|
      t.string :amount
      t.timestamps
    end
  end
end
Neustrony
  • 71
  • 2
  • 11

1 Answers1

2

You need to use accepts_nested_attributes_for here. It allows you to save attributes on associated records through the parent.

class Project < ApplicationRecord
   has_one :budget
   accepts_nested_attributes_for :budget
end

In this case you need a standard routes and a form for a project: <%= simple_form_for @project do |f| %>

In params you'll get a hash budget_attributes: {} inside project_params, so you don't need to create a budget separately.

And you need to change your migrations. If your Budget really belongs_to to the Project, then budgets table need to store project_id, and you have vice versa.

Controller

def new
  @project = Project.new
end

def create
  @project = Project.new(project_params)


  respond_to do |format|
    if @project.save
      format.html { redirect_to projects_path, notice: 'Success' }
    else
      format.html { render :new, notice: 'Project went wrong' }
    end
  end
end

private
def project_params
  params.require(:project).permit(budget_attributes: [:id, :name])
end

You can read more about it here

Vasilisa
  • 4,604
  • 3
  • 20
  • 25
  • Thanks ! Unfortunately even with that line is still got the "missing attribute error", I guess I still have an error regarding foreign keys or something like that – Neustrony Jan 29 '18 at 11:20
  • If I replace has_one by belings_to, it's working. To use has_one I need to manualy add a project_id column in budget model. I don't understand why though – Neustrony Jan 29 '18 at 11:33
  • @Neustrony, I've updated my answer. You have wrong association either in models or migrations. Check it, please. And you can't have `belongs_to` on the both sides of the association – Vasilisa Jan 29 '18 at 12:26
  • but active record should deal with the columns all alone ? I remember that when I did use references and models associations, everything was automatically added by active record, why it can't be the case here ? – Neustrony Jan 29 '18 at 13:48
  • Even with accepts_nested_attributes_for and correct migrations, my attributes are not nested in rails, I've got project=>{...}, budget=>{...} separated then – Neustrony Jan 29 '18 at 13:51
  • @Neustrony, could you please update the code in the question in accordance with what you have now? And you don't need to define the separate `@budget` in the controller. – Vasilisa Jan 29 '18 at 14:04
  • @Neustrony `belongs_to :project` not `projectS`. `accepts_nested_attributes_for :google_adword_budget` - what is a google_adword_budget?! And migrations are still incorrect. And there is `@budget` still... – Vasilisa Jan 29 '18 at 14:27
  • Damn, how did I miss that extra S.. Now it seems to work, I still need to understand, it seems strange to me to need to have references in both tables, especially when I needed to add one manualy to make it work, I guess there's better way. Thanks for all the help provided, I try to clarify everything and then I report what I have – Neustrony Jan 29 '18 at 14:40
  • @Neustrony you don't need references in both tables. You need only one. If the Budget belongs_to to the Project, then budgets table needs to store project_id, but projects table doesn't need any references columns. Please, read one more time about `belongs_to` association in the RailsGuides – Vasilisa Jan 29 '18 at 14:48