解决过分 DRY 或不够 DRY 问题,可简单定 2 个原则:
最短且最好理解的版本:
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 下也能接受。
最后的参考是 rails 的实现:ActiveSupport/TimeWithZone.html#method-i-as_json
如果没有复杂业务逻辑和需要一些第三方 gem 的,只是对 redis 的操作,这个业务场景没必要用 rails,单纯用 grape 这个框架都会性能倍升,并还是在 ruby 这个语言 scope 内。而 rails 的光是启动一个实例就加载上百个 Initializer 策略(实测 130 个),楼主描述的场景(完全实时查询)rails 提供的很多缓存策略都用不上,有力使不上劲的感觉,一开始框架选型就不妥了。
这个就是 draper 的 delegate_all 实现,而 draper 就是装饰器模式的典型使用场景
DHH、林志颖、韩寒三大跨界开赛车的男神
before_create do
article.increment!(:likes_count)
end
这个已经改变了业务逻辑:先累加赞,再添加赞记录。
一个思路是把这类计数器累加操作可以放入队列里异步、顺序执行。
另外我的使用 counter_culture+pg 经验中发在多线程高并发时,累加值容易互相覆盖,最好还是定时或在某些 callback 再 call 一个 update_counter_by_counts
有意义的,意思就是如果你打算做很 care 性能的产品,就选 py 驱动的框架;如果很 care 能否快速实现、需求变化频繁、组件丰富拿来就用、care 开发人员情绪的,就顺便考虑下 rails
说起 CI 时间的话,想起 4 年前的一个 rails 项目,CI 上跑一次完整回归大概 5 个多小时
楼主也叫 Rain?缘分
赞同楼主,crontab 在多实例部署就有容易有问题,另外无重试、统计,精度到分钟级别,顶多算个触发器,是比较粗糙的解决方案,不过也能解决 80% 的早期项目需求。跟 sidekiq 结合是不错的实践,可充分利用 slidekiq 的重试、统计。
#5 楼 @freefishz 那个是163
的数据,没有错
#3 楼 @gihnius #2 楼 具体实践总结
中 blog 的部分都是发表到了公司官网 blog 上的了:http://www.beansmile.com/blog
#2 楼 @lgn21st 发布匆忙忘了说明,具体实践总结
中 blog 的部分都是发表到了公司官网 blog 上的了:http://www.beansmile.com/blog ,其他一些是内部资料不方便公开望见谅,欢迎面交 。
恭喜 @fredwu 加入新公司,开始新事业,结尾不应该是The End
应该是 To be continued
嘛
楼主不知道有个 openid 标准?曾经有时间各大 IT 服务商都支持了,包括 AOL, Blogger, Flickr, Google, Amazon.com, Microsoft, Facebook
非常能理解楼主需求,一套可重用的 CMS 框架,可以满足很多无需太多定制要求的项目,极大减少开发量,例如:
The compiler is written in Crystal
每当看到这种能自举的编程语言就有种“通透”的感觉,上次是看到有印象的是 coffeescript The CoffeeScript compiler is itself written in CoffeeScript
,非常有意思
@楼主 最好的 cucumber 代码 example 是 rspec 内核的测试代码:https://github.com/rspec/rspec-core/tree/master/features
而最好的 rspec 代码 example,自然是由 cucmber 提供:https://github.com/cucumber/cucumber-ruby/tree/master/spec/cucumber
从 web 项目的角度,很少会只测试 controller action 而不测试 view 或路由(除非是做功能扩展型的 gem 开发),而集成测试会覆盖到路由、action 及 view,更符合 web 项目的实现思路,更多的边界测试可以由单元测试来保证,这样既保证了开发效率也有质量,我们团队从 rails3 时代开始就只做集成测试和单元测试,也正是如此考虑,我想 DHH 这个决策也是顺势而为。
如果留意 rails 的变更历史,不难发现 Rails 一直在根据流行的 best practice 来进行内构调整,从最早的功能全包,如包含树形结构、分页,然后又剥离出去;从内置 prototype.js 到改为可选 js 框架。这些改动都是先有之(便利),再改进为可配置(灵活),无一不是为了方便开发者着想。
以前这个场景是用一个 gem grouped_validations 实现,DSL 如下:
validation_group :name, :if => :ready? do
validates_presence_of :first_name
validates_presence_of :last_name
end
不过好久没更新了,想不到这个 feature 变成刚需特性给 rails5 内置了,rails 开发真心爽快
@楼主 在 erb 中 concat buffer 有 2 种做法:一种是用原生的模板语法<%= var %>
,类似 php 5.4 里的 short tag <?=
;
另一种就像你这样操作 output buffer,但在 sinatra 里有比较简单/标准的做法:
# app.rb
helpers do
def echo(str) @_out_buf << str.to_s end
end
# index.erb
<% echo 'hi' %>
anyway,楼主探索 ActionView 的技巧分享值得点赞
唐凤
绝对是传奇之最没有之一,「她」之前可不是女程序员
有个 toy 级别的用 ruby 来写 react-native app: https://github.com/zetachang/opal-native
11 点刚发现这个问题,huacnlee 同学就解决了,赞