0

I am new to Rails, and I'm having trouble with inserting new records into the database using my Car model.

The application is as follow: I have build the articles basic tutorial application as defined in the Rails official website, until section 5.9

I added user authentication useing devise, and I wanted to add a model -cars - that has assosiation with the user. user has_many cars, and a car belongs_to a user. This is the user.rb model file:

class User < ApplicationRecord
 # Include default devise modules. Others available are:
 # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
 devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :validatable
 has_many :cars
end

The cars.rb file is:

class Car < ApplicationRecord
belongs_to :user
end

The cars table is structed like so:

class CreateCars < ActiveRecord::Migration[6.0]
  def change
    create_table :cars do |t|
      t.string :title
      t.text :description
      t.string :img

      t.timestamps
    end
  end
end

I added user assosiation with:

class AddUserIdToCars < ActiveRecord::Migration[6.0]
  def change
    add_column :cars, :user_id, :integer
  end
end

Now, when I use rails console I see that the cars table and user table are created, and creating users works fine.

Alse, when I try to create a new car, I'm redirected back to my car list, and nothing is loaded, and when I check the console I see that the cars table is empty.

the cars controller is:

class CarsController < ApplicationController
    def index
        @cars = Car.all
    end
    def new
    end
    def show
        @car = Car.find(params[:id])
    end
    def create
        # render plain: params[:car].inspect
        @car = Car.new(car_params)
        @car.save
        redirect_to @car
    end
    private
    def car_params
        params.require(:car).permit(:title, :description, :img)
    end
end

the cars/new view is:

<h1>Add new car</h1>

<%= form_with scope: :car,
url: cars_path,
local: true do |form| %>
  <p>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
  </p>

  <p>
    <%= form.label :description %><br>
    <%= form.text_area :description %>
  </p>

    <p>
    <%= form.label :img %><br>
    <%= form.text_area :img %>
  </p>

  <p>
    <%= form.submit %>
  </p>
<% end %>
<%= link_to 'Back', cars_path %>

and the cars index view is:

<h1>Listing cars</h1>

<table>
  <tr>
    <th>Title</th>
    <th>description</th>
    <th>Img</th>
  </tr>

  <% @cars.each do |car| %>
    <tr>
      <td><%= car.title %></td>
      <td><%= car.description %></td>
      <td><%= car.img %></td>

      <td>
      <%= link_to 'Show', car_path(car) %>
      </td>
    </tr>
  <% end %>
</table>

<%= link_to 'New Car', new_car_path %>

when I post a new car or go to index page, there is no error, and the very same structure in the article section (that I created with the rails official tutorial) works fine.

When I navigate to path/cars or when I submit a new car I see an empty table. When I try to use show, by navigating to cars/:id, there is an error that no car with this id exist - another testemony that no records are inserted.

I'm very new to Rails, so I'm sorry if there is not enough info/I shared to much info. If more info is needed please tell me.

I have seen most questions with similar topics, and didn't find any relavent answer there. I saw this, among others:

Insert into Rails Database

Rails 4 not inserting values into database

Ruby on Rails not adding record to database

Rails 5: ActiveRecord not creating record

This is the rails log for create cars

Started POST "/cars" for ::1 at 2019-10-20 16:46:15 +0300 Processing by CarsController#create as HTML Parameters: {"authenticity_token"=>"MZYIt+YOELCPSFbZZmammwr7LrdMWQfzlge3k/h8UftwBjqgzHHH9VqHBFHAiwXi2Ej2Y4jM2xhC/V7sil773Q==", "car"=>{"title"=>"car3", "description"=>"123123", "img"=>"123"}, "commit"=>"Save Car"} Redirected to localhost:3000/cars Completed 302 Found in 5ms (ActiveRecord: 0.0ms | Allocations: 1322

Why no car is being inserted while an article does, even tough the functions and erb files are practicaly the same?

sureshprasanna70
  • 1,043
  • 1
  • 10
  • 27
mizenetofa1989
  • 117
  • 2
  • 16
  • Show us your rails logs while inserting a new car. The logs can be found at `log/development.log`. – sureshprasanna70 Oct 20 '19 at 13:41
  • @sureshprasanna70 is this the relevant part? Started POST "/cars" for ::1 at 2019-10-20 16:46:15 +0300 Processing by CarsController#create as HTML Parameters: {"authenticity_token"=>"MZYIt+YOELCPSFbZZmammwr7LrdMWQfzlge3k/h8UftwBjqgzHHH9VqHBFHAiwXi2Ej2Y4jM2xhC/V7sil773Q==", "car"=>{"title"=>"car3", "description"=>"123123", "img"=>"123"}, "commit"=>"Save Car"} Redirected to http://localhost:3000/cars Completed 302 Found in 5ms (ActiveRecord: 0.0ms | Allocations: 1322 – mizenetofa1989 Oct 20 '19 at 13:48

1 Answers1

0

Looks like you're on rails 6. So, by default, when a Car belongs_to :user, then user_id on @car is required. But, in your create action, you're never setting user_id on @car, so @car is not saving.

If you think a save is supposed to be working and it's not, you can always do save! instead of save. The banged version of the method will raise an error if the save is unsuccessful.

Anyway, I think the create action in your CarsController ought to look something more like:

class CarsController < ApplicationController

  def index
    @cars = Car.all
  end

  def new
    @car = Car.new
  end

  def show
    @car = Car.find(params[:id])
  end

  def create
    @car = current_user.cars.new(car_params)
    if @car.save
      redirect_to @car
    else
      # do something else
    end
  end

  private

  def car_params
    params.require(:car).permit(:title, :description, :img)
  end

end

By doing current_user.cars.new, user_id is automatically set on the new Car and you should be able to save.

In response to your questions in comments:

Why current_user.cars.new(car_params) and not: current_user.Car.new(car_params)? Why no capital Car was needed, like in Car.find?

Car is a class. Car.new calls the new method on the Car class. Car.find calls the find method on the Car class. Car is not a method on current_user. Therefore, current_user.Car makes no sense and should throw an error.

cars (when used like current_user.cars) is a method on the current_user instance of User. The .cars method is created when you do User has_many :cars. You can see a listing of all the methods created by has_many in the Methods Added by has_many section of the Active Record Associations guide.

current_user.cars returns an ActiveRecord_Relation. When you do current_user.cars.new, you're calling the new method on the ActiveRecord_Relation returned by current_user.cars. This new method returns an instance of Car that already has user_id set, which is the point of the whole thing. So:

  1. Car.new returns a new Car without user_id set,
  2. current_user.cars.new returns a new Car with user_id set.

why cars? as I understand, cars is a refrens to the table, and not the car model itself.

No. As stated above, and in this context, cars is a method on current_user that is created when you do User has_many :cars and that returns a ActiveRecord_Relation representing all of the Car instances that have a user_id that matches current_user.id.

jvillian
  • 19,953
  • 5
  • 31
  • 44
  • Works like a charm. Thanks! Just two last questions: 1) Why current_user.cars.new(car_params) and not: current_user.Car.new(car_params)? Why no capital Car was needed, like in Car.find? 2) why cars? as I understand, cars is a refrens to the table, and not the car model itself. – mizenetofa1989 Oct 23 '19 at 13:38
  • 1
    See updated answer with responses to your questions. – jvillian Oct 23 '19 at 15:56
  • Thanks again. You are a life saver – mizenetofa1989 Oct 23 '19 at 16:02