Skip to content

Instantly share code, notes, and snippets.

@anka
Created February 17, 2015 19:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anka/56aeae44812041a29aba to your computer and use it in GitHub Desktop.
Save anka/56aeae44812041a29aba to your computer and use it in GitHub Desktop.
Setting default values for has_one association
class User < ActiveRecord::Base
# Adding the subscription association and set
# the desired kind of the subscription
has_one :subscription, -> {where kind: Subscription.kinds[:single]}
end
class Subscription < ActiveRecord::Base
# Adding an enum with predefined values
enum kind: {single: 2, company: 7}
belongs_to :user
end
# Testing the assocation
# After building a subscription the kind will
# be preset to 2
@user = User.new
@user.build_subscription
=> #<Subscription id: nil, user_id: nil, kind: 2, name: nil, note: nil, created_at: nil, updated_at: nil>
@ramonrails
Copy link

ramonrails commented Jun 15, 2020

This is a good way to set default values for has_one association
But, for a business use case?

Pros:

  • Integer uses less space (for large data sets)
  • possible => subscription.single!, subscription.single? subscription.kind

Cons:

  • in this code, user can only have either single or company subscription (but, it may be the required business logic)
  • Publishing an API would be costly (on time, consumer effort/learning-curve)
    • need serving the string instead of integer (to make it easy for API consumer). More processing on each call! Scalable?
    • confuse the consuming user with integer values (of not served strings). Discouraging less experienced interested parties?
    • consumer to remember the mapping
    • documentation will be needed for this column
  • If the API is designed in another framework (like node), then
    • mapping business logic needs knowledge transfer
  • tomorrow, when enum increases to 5 values, all above must be repeated again!
    • more code
    • more processing on each API call
    • more documentation
    • more manual work to keep all API consumers aligned
  • business logic for single/company
    • will require lof of ifs
    • bloated User model, or split into modules and include

Alternate solution is STI

SingleSubscription < Subscription
CompanySubscription < Subscription

Pros:

  • Super easy to use in the code (maintainable)
  • User can have both subscriptions together
  • no lambda evaluation (less work for ruby/AR/rails)
  • publishing API is super easy
    • No documentation required for this column
    • consumer will see data and understand. easy.
    • more bytes but less processing per API call. internet bandwidth and storage is cheap now. No?
    • write on node, or any other framework. easy. No need to copy mapping business logic to node.
    • less code in serving the API. No need to map it back to string
  • when "type" increases to 5 or more values
    • no extra documentation needed. scalable.
    • no extra work to keep API consumers aligned. scalable.
    • increase as many values as you need. scalable.
    • an ML system can start making sense without being fed the business logic
  • less experienced developers become productive faster
  • business logic for single/company
    • does not bloat the user model
    • stays refactored in separate classes (no need to include modules to reduce the fat model)

Cons:

  • "SingleSubscription" in DB takes more bytes per tuple than an integer. But then why not using bits instead of booleans?
  • More bytes to pass to an API call. But it's flawlessly and easily scalable for third parties.

Just my opinion. Discardable at your free will 😀
Have a wonderful year ahead. (Despite the pandemic, Yes)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment