Create action in controller is omitting reference field

Viewed 41

I have a problem with my rails application when i create a customer for an environment, the action itself if omitting the parameter environment_id in the insert statment.

This is my customer.rb model:

class Customer < ActiveRecord::Base
  belongs_to :environment, inverse_of: :customers

  has_many :all_services, class_name: 'Service'
  has_many :services, inverse_of: :customer

  has_paper_trail ignore: %i[created_at updated_at]
end

This is my environment.rb model:

class Environment < ActiveRecord::Base
  has_many :all_customers, class_name: 'Customer', dependent: :destroy
  has_many :customers, inverse_of: :environment

  has_many :all_services, class_name: 'Service', dependent: :destroy
  has_many :services, inverse_of: :environment

  has_many :all_versions, class_name: 'Version', dependent: :destroy
  has_many :versions, inverse_of: :environment

  has_many :all_role_permissions, class_name: 'RolePermission', dependent: :destroy
  has_many :role_permissions, inverse_of: :environment

  has_paper_trail ignore: %i[created_at updated_at]
end

This is the customer_controller.rb create action:

def create
 if customer_params.permitted?
  render json: Customer.create!(customer_params), status: :ok
 else
  render json: { message: Api::V1::INVALID_PARAMETERS }, status: :bad_request
 end
end

def customer_params
 params.require(:customer).permit(:environment_id, :full_name, :document_type, :document_value, :customer_type)
end

And this is the server log:

Started POST "/api/v1/customers" for 127.0.0.1 at 2021-06-02 18:18:44 +0100
Processing by Api::V1::CustomersController#create as HTML
  Parameters: {"full_name"=>"cvbcv", "document_type"=>"bcvbc", "document_value"=>"vbcvbcv", "customer_type"=>"bcvbcvb", "environment_id"=>1, "customer"=>{"full_name"=>"cvbcv", "document_type"=>"bcvbc", "document_value"=>"vbcvbcv", "customer_type"=>"bcvbcvb", "environment_id"=>1}}
  User Load (0.7ms)  SELECT "users".* FROM "users" WHERE "users"."uid" = $1 LIMIT $2  [["uid", "test1@test.cl"], ["LIMIT", 1]]
   (0.5ms)  BEGIN
  ↳ app/services/api/customers.rb:20:in `create_customer'
  Environment Load (0.5ms)  SELECT "environments".* FROM "environments" WHERE "environments"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/services/api/customers.rb:20:in `create_customer'
  Customer Create (1.4ms)  INSERT INTO "customers" ("full_name", "document_type", "document_value", "customer_type", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["full_name", "cvbcv"], ["document_type", "bcvbc"], ["document_value", "vbcvbcv"], ["customer_type", "bcvbcvb"], ["created_at", "2021-06-02 17:18:44.378509"], ["updated_at", "2021-06-02 17:18:44.378509"]]
  ↳ app/services/api/customers.rb:20:in `create_customer'
   (1.2ms)  ROLLBACK
  ↳ app/services/api/customers.rb:20:in `create_customer'
Completed 500 Internal Server Error in 22ms (ActiveRecord: 4.3ms | Allocations: 6384)


  
ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR:  null value in column "environment_id" violates not-null constraint
DETAIL:  Failing row contains (28, cvbcv, bcvbc, vbcvbcv, bcvbcvb, null, 2021-06-02 17:18:44.378509, 2021-06-02 17:18:44.378509).
):

I tried everything i can possible know, i triple checked the migrations and schema. I also checked active record gem version from previous projects and everything is ok.

One thing that might be relevant, this that the project have a front-end in Angular.

2 Answers

Rails validates for Environment presence in the database because Customer belongs_to to it.

Query below in your log is trying to load Environment with ID=1:

Environment Load (0.5ms)  SELECT "environments".* FROM "environments" WHERE "environments"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]

After this Rails try to INSERT new Customer without Environment reference because it seems that Environment with ID=1 doesn't exist in the database.

multiple ways of solving it. problem: the environment_id is nil and already as not nil defined in the postgres DB.

  • you can add a required: true to the association, which rails then checks for existence. in your case a validation error would throw.

  • you can add a validates :enviroment_id, presence: true which would do the same

  • you merge the id into the params

example to always merge the environment_id into the params

def customer_params
 params.require(:customer).permit(:full_name, :document_type, :document_value, :customer_type).merge(environment_id: GET_ME_THE_ENV_ID)
end
Related