• Why Sometimes I Write WET Code at 2018年09月16日

    解决过分DRY或不够DRY问题,可简单定2个原则:

    1. 不过早“优化” - 先不要假想着将来会有人“重用”这个方法,将来太多不确定性。
    2. “事不过三”原则 - 出现2处重复不过份,当第3次出现重复时就要考虑DRY一下了。(Tips:可以利用工具如rubycritic、flay 或 flay 等来帮忙找出重复的地方)
  • 最短且最好理解的版本:

    arr.inject({}) {|r, (k,v)| r.merge({k => v.to_i + r[k].to_i}) }
    or 
    arr.inject(Hash.new(0)) {|r, (k,v)| r[k] += v.to_i; r }
    
  • 使用本地存储时如果是单机应用还要考虑文件过多问题,carrierwave 提供了hook可以实现partitioning以及文件删除后的文件夹清扫,Disk Service不知道提供了接口没

  • 我吐槽的是rails的代码组织和命名 :)

  • 要想模仿ActiveRecord的要慎重,这是个“PhotoShop”级别的库,包含各种想得到或者你觉得现在没用将来很需要的特性。

    看下rails 5.1.4 中ActiveRecord 定义的module有150多个(不包含Class及子module)

    ActiveRecord::Attributes,
    ActiveRecord::Migration,
    ActiveRecord::ExplainRegistry,
    ActiveRecord::Migrator,
    ActiveRecord::Fixture,
    ActiveRecord::NoDatabaseError,
    ActiveRecord::ConnectionTimeoutError,
    ActiveRecord::ExclusiveConnectionTimeoutError,
    ActiveRecord::QueryCache,
    ActiveRecord::Core,
    ActiveRecord::ConnectionHandling,
    ActiveRecord::CounterCache,
    ActiveRecord::DynamicMatchers,
    ActiveRecord::Enum,
    ActiveRecord::InternalMetadata,
    ActiveRecord::Explain,
    ActiveRecord::Inheritance,
    ActiveRecord::ModelSchema,
    ActiveRecord::NestedAttributes,
    ActiveRecord::NoTouching,
    ActiveRecord::TouchLater,
    ActiveRecord::Persistence,
    ActiveRecord::Querying,
    ActiveRecord::CollectionCacheKey,
    ActiveRecord::ReadonlyAttributes,
    ActiveRecord::RecordInvalid,
    ActiveRecord::Reflection,
    ActiveRecord::RuntimeRegistry,
    ActiveRecord::Sanitization,
    ActiveRecord::Schema,
    ActiveRecord::SchemaDumper,
    ActiveRecord::SchemaMigration,
    ActiveRecord::Scoping,
    ActiveRecord::Serialization,
    ActiveRecord::StatementCache,
    ActiveRecord::Suppressor,
    ActiveRecord::Timestamp,
    ActiveRecord::Transactions,
    ActiveRecord::Translation,
    ActiveRecord::Validations,
    ActiveRecord::SecureToken,
    ActiveRecord::ActiveRecordError,
    ActiveRecord::ConnectionNotEstablished,
    ActiveRecord::ConnectionAdapters,
    ActiveRecord::Aggregations,
    ActiveRecord::Associations,
    ActiveRecord::AttributeAssignment,
    ActiveRecord::AttributeMethods,
    ActiveRecord::AutosaveAssociation,
    ActiveRecord::Attribute,
    ActiveRecord::LegacyYamlAdapter,
    ActiveRecord::AssociationRelation,
    ActiveRecord::NullRelation,
    ActiveRecord::Relation,
    ActiveRecord::QueryMethods,
    ActiveRecord::PredicateBuilder,
    ActiveRecord::SpawnMethods,
    ActiveRecord::FinderMethods,
    ActiveRecord::Batches,
    ActiveRecord::Result,
    ActiveRecord::TableMetadata,
    ActiveRecord::Delegation,
    ActiveRecord::VERSION,
    ActiveRecord::SerializationTypeMismatch,
    ActiveRecord::Coders,
    ActiveRecord::RecordNotFound,
    ActiveRecord::AdapterNotSpecified,
    ActiveRecord::AssociationTypeMismatch,
    ActiveRecord::AssociationNotFoundError,
    ActiveRecord::RecordNotSaved,
    ActiveRecord::Locking,
    ActiveRecord::RecordNotDestroyed,
    ActiveRecord::RecordNotUnique,
    ActiveRecord::InvalidForeignKey,
    ActiveRecord::AdapterNotFound,
    ActiveRecord::SubclassNotFound,
    ActiveRecord::HasManyThroughOrderError,
    ActiveRecord::WrappedDatabaseException,
    ActiveRecord::NotNullViolation,
    ActiveRecord::ValueTooLong,
    ActiveRecord::MismatchedForeignKey,
    ActiveRecord::PreparedStatementCacheExpired,
    ActiveRecord::PreparedStatementInvalid,
    ActiveRecord::HasManyThroughAssociationNotFoundError,
    ActiveRecord::StaleObjectError,
    ActiveRecord::ReadOnlyRecord,
    ActiveRecord::AttributeAssignmentError,
    ActiveRecord::MultiparameterAssignmentErrors,
    ActiveRecord::UnknownPrimaryKey,
    ActiveRecord::AttributeSet,
    ActiveRecord::ImmutableRelation,
    ActiveRecord::TransactionRollbackError,
    ActiveModel::UnknownAttributeError,
    ActiveRecord::Deadlocked,
    ActiveRecord::SerializationFailure,
    ActiveRecord::HasManyThroughCantDissociateNewRecords,
    ActiveRecord::IrreversibleOrderError,
    ActiveRecord::HasManyThroughNestedAssociationsAreReadonly,
    ActiveRecord::HasManyThroughAssociationPolymorphicSourceError,
    ActiveRecord::TestFixtures,
    ActiveRecord::HasManyThroughAssociationPolymorphicThroughError,
    ActiveRecord::DeleteRestrictionError,
    ActiveRecord::HasManyThroughAssociationPointlessSourceTypeError,
    ActiveRecord::HasOneThroughCantAssociateThroughCollection,
    ActiveRecord::HasOneAssociationPolymorphicThroughError,
    ActiveRecord::InverseOfAssociationNotFoundError,
    ActiveRecord::Store,
    ActiveRecord::AttributeDecorators,
    ActiveRecord::LazyAttributeHash,
    ActiveRecord::ThroughCantAssociateThroughHasOneOrManyReflection,
    ActiveRecord::ReadOnlyAssociation,
    ActiveRecord::AmbiguousSourceReflectionForThroughAssociation,
    ActiveRecord::FixtureSet,
    ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection,
    ActiveRecord::HasOneThroughCantAssociateThroughHasOneOrManyReflection,
    ActiveRecord::HasManyThroughCantAssociateNewRecords,
    ActiveRecord::HasManyThroughSourceAssociationNotFoundError,
    ActiveRecord::ThroughNestedAssociationsAreReadonly,
    ActiveRecord::Integration,
    ActiveRecord::Base,
    ActiveRecord::EagerLoadPolymorphicError,
    ActiveRecord::StatementInvalid,
    ActiveRecord::AttributeMutationTracker,
    ActiveRecord::ExplainSubscriber,
    ActiveRecord::Calculations,
    ActiveRecord::MigrationError,
    ActiveRecord::IrreversibleMigration,
    ActiveRecord::DuplicateMigrationVersionError,
    ActiveRecord::DuplicateMigrationNameError,
    ActiveRecord::UnknownMigrationVersionError,
    ActiveRecord::IllegalMigrationNameError,
    ActiveRecord::PendingMigrationError,
    ActiveRecord::ConcurrentMigrationError,
    ActiveRecord::NoEnvironmentInSchemaError,
    ActiveRecord::ProtectedEnvironmentError,
    ActiveRecord::Type,
    ActiveRecord::EnvironmentMismatchError,
    ActiveRecord::DefineCallbacks,
    ActiveRecord::LogSubscriber,
    ActiveRecord::SuppressorRegistry,
    ActiveRecord::TypeCaster,
    ActiveRecord::Callbacks,
    ActiveRecord::Railties,
    ActiveRecord::NullMutationTracker,
    ActiveRecord::DangerousAttributeError,
    ActiveRecord::HasOneThroughNestedAssociationsAreReadonly,
    ActiveRecord::ConfigurationError,
    ActiveRecord::Railtie,
    ActiveRecord::FixtureClassNotFound,
    ActiveRecord::MigrationProxy,
    ActiveRecord::NullMigration,
    ActiveRecord::TypeConflictError,
    ActiveRecord::RangeError,
    ActiveRecord::TransactionIsolationError,
    ActiveRecord::Rollback,
    ActiveRecord::Tasks
    

    一般人用得最多的是 Migration、Validations、Scoping、Attributes、AttributeMethods、Callbacks、FinderMethods、QueryMethods、CounterCache、Associations等module提供的DSL。

    有些高级点如Locking、Store、SpawnMethods(提供merge合并其他model的scoping)、QueryCache(不少人不知道可在rake task中显式使用)、TouchLater、SecureToken(提供generate_unique_secure_token)、PredicateBuilder(定制query的predicate)、Aggregations(提供composed_of macro)、Suppressor(临时跳过save操作)在所适应的场景中很便利却容易被忽略。

    另外想吐槽一点是各种Error module 没有放到一个Error namespace下,或者放到与feature 同名的module下也能接受。

  • JSON中时间对象的输出格式是怎么定义的?

    最后的参考是rails的实现:ActiveSupport/TimeWithZone.html#method-i-as_json

  • 如果没有复杂业务逻辑和需要一些第三方gem的,只是对redis的操作,这个业务场景没必要用rails,单纯用grape这个框架都会性能倍升,并还是在ruby这个语言scope内。而rails的光是启动一个实例就加载上百个Initializer策略(实测130个),楼主描述的场景(完全实时查询)rails提供的很多缓存策略都用不上,有力使不上劲的感觉,一开始框架选型就不妥了。

  • Rails 5.1 add delegate_missing_to at 2017年07月21日

    这个就是 draper 的delegate_all 实现,而draper就是装饰器模式的典型使用场景

  • DHH、林志颖、韩寒三大跨界开赛车的男神

  • before_create do
      article.increment!(:likes_count)
    end
    

    这个已经改变了业务逻辑:先累加赞,再添加赞记录。

    一个思路是把这类计数器累加操作可以放入队列里异步、顺序执行。

    另外我的使用counter_culture+pg 经验中发在多线程高并发时,累加值容易互相覆盖,最好还是定时或在某些callback再call 一个update_counter_by_counts