Comments (8)
Okay, so I thought about it a bit, and I got two ideas:
First of all, how it works now:
- The masker return value is simply passed to the SQL
UPDATE
command. Model attribute writers are not involved. - By default, name of the column to be updated is derived from the attribute name, but it can be overwritten with
column_name
option.
We can easily enhance it in a following way:
- An array of column names can be passed as
column_names
option. If so, the masker's return value is expected to be an array as well, and its subsequent elements are update values for corresponding columns.
Example:
Here we're setting some agreed password for every user so that developers can log in as anyone they want. Password digest and salt are stored in separate columns.
class User
attr_masker :password, column_names: ["password_digest", "password_salt"], masker: proc do
new_password = "verysecret"
salt = generate_random_salt()
digest = encrypt_password(new_password, salt)
[digest, salt]
end
end
The masker's return value will be used in update operation like this one:
User.update(user.id, {password_digest: masker_retval[0], password_hash: masker_retval[1]})
However I am also thinking about a more radical change:
- The masker's return value is assigned to model's attribute via respective attribute writer method.
- The attribute writer may have arbitrary side effects. In particular, it may alter more than one database fields (see example below).
- However only changes made to fields specified in
column_names
option are saved. All other changes are discarded. Thecolumn_names
option defaults to one-element array containing the attribute name.
Example:
class User
attr_masker :password, masker: proc { "verysecret" }, column_names: ["password_hash", "password_salt"]
def password=(new_password)
self.password_salt = salt = generate_random_salt()
self.password_hash = encrypt_password(new_password, salt)
end
end
Consequences of this approach are as follows:
- It must be user's responsibility to ensure that the attribute writer is safe to use. For example, it could perform a database update (and that will happen before other attributes get reverted!), or some junk could be uploaded to S3, overwriting production pictures. On the other hand,
:if
, and:unless
filters may also call model methods, so maybe it's not that bad. (But typically they will rely on getter methods and are far less likely to break anything). - Since we're working on models, it should be possible to validate them before saving.
from attr_masker.
@ribose-jeffreylau Your input here is very welcome. I'd really like to know the usage example for the column_name
option before I make any radical changes.
from attr_masker.
@skalee
For our current use case, it is actually very similar to the one you just posted above.
We use attr_encrypted alongside attr_masker. Using attr_encrypted means there would be some columns that are renamed to encrypted_old_column_name
instead of just old_column_name
.
In our test environment, we also want to be able to mask the column old_column_name
. This is where :column_name
comes into play.
Your proposed solution looks like it could handle this situation well.
from attr_masker.
Thanks @ribose-jeffreylau for the clarification, @skalee let's proceed, thanks!
from attr_masker.
@skalee I agree that the solution to #51 is this. The attribute writer can support "super" so that all necessary attribute writer modifiers are applied prior to masking.
I thought the tricky part is how to ensure attr_masker is in the attribute-writers chain, but that said all overrides to the attribute writer would technically have to call super so it won't be an issue.
Let's go ahead, thanks!
from attr_masker.
As for now, attr_masker does not use attribute writers at all.
from attr_masker.
Got it, let's do it. 👍
from attr_masker.
The column_name
option has been introduced in #53.
from attr_masker.
Related Issues (20)
- Weird random failures in GitHub Actions on Ruby 2.7 HOT 1
- Enhancement: Brand new DSL HOT 11
- DatabaseCleaner error when running RSpec HOT 5
- Update for Ruby 3
- Drop support for Rails 4.2 and some older Rubies
- Update Database Cleaner HOT 1
- Add support for global config file HOT 2
- I want you to be able to create PR HOT 2
- Support Rails 5.2
- Update for Rails 6 HOT 1
- Migrate CI to GitHub Actions HOT 3
- Weird specs output HOT 1
- Investigate "low" test coverage HOT 3
- Update for Rails 6.1
- Update for Ruby 3.0 HOT 4
- Update for modular Database Cleaner HOT 1
- Weird test failures HOT 1
- Bring CodeCov back HOT 3
- Tests failing for Rails 4.2 with Ruby 2.4, 2.5 and 2.6
- Make new release after #96 HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from attr_masker.