Skip to content

Instantly share code, notes, and snippets.

@srghma
Last active August 2, 2018 14:08
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 srghma/9f686ea62f5bd41583c3284459127916 to your computer and use it in GitHub Desktop.
Save srghma/9f686ea62f5bd41583c3284459127916 to your computer and use it in GitHub Desktop.
what I have learned, while doing XXX

Project specification:

ecommerce + news

Technologies:

Cool stuff, as the result of development process:

What I realized:

  1. I hate ruby

I can't just have function, I always have to wrap it in some mumbo-jumbo.

  1. print_dump

There was a time when I needed to test admin panel in context of successful checkout. The first thought was to automate pg_dump after checkout and make pg_restore before admin panel test. Its good that I decided not to do this. Instead I use seed_dump gem

# spec/config/dump_record.rb
module DumpRecord
  def print_dump_record(*args)
    puts dump_record(*args)
  end

  def print_dump_records(*args)
    puts dump_records(*args)
  end

  def dump_record(record, options = {})
    dump_records([record], options)
  end

  def dump_records(records, options = {})
    io = StringIO.new

    call_private_instance_method(
      SeedDump::DumpMethods,
      :write_records_to_io,
      records,
      io,
      options
    )
  end

  private

  def call_private_instance_method(module_, method, *args)
    klass = Class.new do
      include module_
    end

    klass.new.__send__(method, *args)
  end
end

include DumpRecord

example:

[3] pry(#<RSpec::ExampleGroups::AdminPackageCreate>)> print_dump_records User.all
User.create!([
  {email: "sherman_gusikowski@gulgowskigoodwin.info", encrypted_password: "$2a$04$QS1VlTfZQkB37b8YcDQnk.XfB9DOOcMEDIS56aQIU5aSoI.ylNgPC", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2018-03-03 15:44:37", last_sign_in_at: "2018-03-03 15:44:37", current_sign_in_ip: "172.18.0.4", last_sign_in_ip: "172.18.0.4", confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, slug: "taurean", username: "Taurean", avatar: nil, autogenerated_password: false, role_id: 1, active_book_club_subscription_id: nil, active_magazine_subscription_id: nil, first_name: "Ryan", last_name: "Miller", salutation: "Miss", country: "Lao People's Democratic Republic", state: "California", city: "Hudsonborough", address_line: "1316 Dare Squares", zipcode: "77602", phone: "+820 33 265 2289"}
])
=> nil
[4] pry(#<RSpec::ExampleGroups::AdminPackageCreate>)>

And just copy-paste User.create to let block before test

  1. Flag fields

You should reduce number of possible states field can have.

For example: you have entity product with physical_count number field, but then you have found that product not always have physical_count. Now you want to make physical_count have nil sometimes. But its wrong. It would be better to add physical_count_enabled boolean field.

  1. DB architecture - divide everything!!

The best database architecture is the most dumb.

Each page should have independent tree of tables, prefix each table with page name it belongs to. Dont use polymorphic associations and STI.

If tables have same columns - it's not the reason to extract this columns to some table (example - User and Admin have address fields, don't extract them to table Address), denormalization is fine if it allows you to not load extra entity.

Use postgres unions, views and joins to merge data from different tables.

  1. factory_bot is fine

It's fine to have factory_bot, as long as you are not using traits and create relations outside factory. Think about it as degenerate quickcheck library

  1. config.action_controller.include_all_helpers = false
now:
- user requests page too frequently
- nginx notifies fail2ban
- fail2ban changes iptables
expected:
- user exceeds request limit LIMIT1
- nginx notifies fail2ban
- fail2ban adds user ip to `deny list`
- fail2ban restarts nginx
- nginx shows custom error page to user "hey, you blocked"
- user exceeds request limit LIMIT2
- fail2ban adds user ip to ignored by iptables so that user will not pollute nginx logs
to use fastly (https://robots.thoughtbot.com/a-guide-to-caching-your-rails-application-with-fastly) for example on home page
we have to problems:
csrf
fix - get csrf after page loads using ajax and attach to meta https://www.fastly.com/blog/caching-uncacheable-csrf-security
header shows `login` if user not logged-in and `logout` if logged-in
fix - show home page without `login/logout` fragment, then request fragment from server, pass `session[:current_user_id]` cookie in this request
user should be redirected to active solicitation page (https://www.vdare.com/solicitations/peter-brimelow-help-patriots-defeat-ruling-class-immigration-fanatics) if he didn't seen solicitation (`solicitation_were_seen = cookies["solicitation_#{slug}"].present?`)
fix - have no idea
Proposal:
- dont need fastly at all
- to protect from ddos - use fail2ban
- use cdn to deliver assets
- cache views using rails etags https://apidock.com/rails/ActionController/ConditionalGet/stale%3F
Difference of rails etags and fastly caching:
- fastly - db cant be asked on request to make some desitions, cache can only be invalidated
- rails etag - browser sends to server hash of all inputs that defines that page, and server then decides to render page or send `not changed`, based on data, that he retrieved from db
What I have learned:
- fastly suits better for apis
- will not use `fresh_when` and `etag` methods, but only `stale?` method, because the spread point, where desition is made about render the page or not
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment