0

I have a little -seems simple code that has me knocking my head around the place.

Here is a user model:

class User < ActiveRecord::Base
  has_one :api_account, inverse_of: :user, dependent: :destroy

# Other user-specific validations come after

Here is the associated api_account:

class ApiAccount < ACtiveRecord::Base
  belongs_to :user, inverse_of: :api_account
  validates :access_token, presence: true
  validates :user, presence: true,
                   uniqueness: true

In the api_account controller, I have:

response = ### Some JSON response from a distant server

@api_account = @user.create_api_account(:access_token => response[:access_token])

The schema for the api_account looks like this:

create_table "api_accounts", force: true do |t|
  t.text     "access_token"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.integer  "user_id"
end

add_index "api_account", ["user_id"], name: "index_api_accounts_on_user_id"

Whenever I run the code, I get the access token in the response variable. When I use the rails console to check the database, I see a saved instance with valid creation and update time, but access_token and user_id have nil values.

First off, I still don't understand why these two fields have nil values. And second, why are they saved (i.e. pass validation) with nil values.

Any help would be more than welcome. Though, I sense a face palm coming! :)

igreka
  • 330
  • 3
  • 15
  • 1
    a = ApiAccount.new(:access_token => response[:access_token]) then debug it (check `a.errors` to see validation result). the @user.api_account << a and debug @user.errors – Razor Jan 10 '15 at 18:40
  • There isn't any error message at all. I inspect them in the console; nothing pops up. Could it be that I am assigning attributes to the "api_account" manually and not with strong params? – igreka Jan 12 '15 at 22:37

2 Answers2

1

It turns out that Rails prevents you from using the built-ins "save" and "create" method successfully without "strong parameters".

The workaround is not to save from the controller but within the model itself with a customized function like this:

def CloudAccount.create_or_update(user, provider, token)
 raw_params = {provider: provider, access_token: access_token}
 params     = ActionController::Parameters.new(raw_params)
 if @cloud_account = CloudAccount.find_by(user_id, provider: provider)
   @cloud_account.update(params.permit(:access_token)
 else
   @cloud_account = user.cloud_accounts.create(params.permit(:provider, :access token
end

As you can see, it was just easier to isolate the API access code into a dedicated model and controller that is associated to the user model.

The trick seems to be ActionController::Parameters.new which creates legit params that Rails accepts. Hop this is useful to someone.

igreka
  • 330
  • 3
  • 15
0

@igreka, I think you should try this in your api_account controller like -

@api_account = @user.create_api_account(:access_token => api_account_params)

private

def api_account_params

json_params=ActionController::Parameters.new(JSON.parse(response[:access_token]))

return json_params.require(:api_account).permit!)

end

I hope this could resolve your issue.

Chitra
  • 1,294
  • 2
  • 13
  • 28