3

I have a rails app that like so many rails apps, has users. In my user model i have password and salt columns, among others. Is there any way i can protect these from appearing when i do for example debug @user or when i render JSON?

Of course i could just make sure to omit these every time i use it, but is there a way i can make really sure that they don't show up anywhere?

Maybe they could be private fields? They are only needed in my User model and my Session controller, but i could make a method in User that compares a given password to the correct one and then only have the variables accessible in the ´User´ module. Would this help, or would they still be rendered in those two places ( and others )?

topisani
  • 375
  • 2
  • 17

1 Answers1

4

Very good question, there are several things to consider:

  1. Are you looking to "privatise" the values in the model or in the Rails Core?
  2. Will you need to access these attributes in any specific circumstances? (IE are they always private?)
  3. How will the private methods be populated? Will they ever change?

I have to be honest in saying I don't know the answer. Since I'm interested, I did some research. Here are some resources:

The consensus seems to be that if you take the Rails model, and apply the logic that every time you populate it, its attributes become instance methods of the, you can begin to privatise those methods within the model itself.

For example...

#app/models/user.rb
class User < ActiveRecord::Base
    private :password, :password=
    private :salt, :salt=
end

This seems to give you the ability to make certain methods private in your model, which will answer half your question. However, it still leaves the possibility of ActiveRecord pulling the record each time, which could be a danger.

I had a look into this, and found that there are certain ways you can manipulate ActiveRecord to prevent it pulling unwanted data:

This resource recommends the use of active_record_serializers. This appears specifically for JSON, but is more along the right track (IE the ability to define which data we return from ActiveRecord queries).

#serializer
class UserSerializer < ActiveModel::Serializer
  attributes :username, :created_at
end

#controller
render json: @user, serializer: UserSerializer

There was another suggestion of ActiveRecord Lazy Attributes - stipulating to ActiveRecord which attributes to load:

#app/models/user.rb
class User < ActiveRecord::Base
  attr_lazy :data
end

Finally, you always have good ol' default_scope:

#app/models/user.rb
class User < ActiveRecord::Base
   default_scope select([:id, :username])
end
Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Very good answer! I only need the values inside the user model. I can have a public function to check if a given password is correct, and one to set a new password. I will look into the sources you posted in a bit. – topisani Sep 24 '15 at 07:30