`
seamon
  • 浏览: 22585 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
19c4d30c-d52a-3cc5-b233-a4a7d92b5798
rails3项目解析
浏览量:19656
社区版块
存档分类
最新评论

rails3项目解析之2——rails基础

阅读更多
rails3项目解析之1——系统架构
rails3项目解析之3——redis


rails 3.0是2010年8月份发布的。迄今为止,3.0已历经多个tiny版到了3.0.8。3.1已经放出rc4,看起来离正式版已为期不远。相对于2系,3系还是有一些令人惊喜的变化,而且在架构上也规范和严整了许多。3.1中更是又加入了几个颇为有趣的特性。我们的项目一直都是紧跟rails新版,很欣慰能够毫无道德压力地做一个喜新厌旧常换常新的男人。但什么都追新也吃了不少小苦头,不过仍然死不悔改,大家都在坐等3.1发布试吃。

更多关于rails3的新特性,网上一抓一把,需求和欲望比较强烈的同学可自行解决,在此不再赘述。下面主要说一下我们这个项目。因为项目不大,而且第一期没有太多用户互动的内容,所以涉及到的知识范畴比较小,都是些基础的东西。

1、目录结构

除那些默认目录之外,我们在项目中又另外加了一些自定义的目录来做不同的事情。

1.1 errros/。在app/目录之下,内容是各种自定义的XxxError类。使用异常机制能够使得代码更加清晰,流程语义更准确,更好地实现模块化的程序结构。

1.2 validators/。在app/目录之下,内容是继承自ActiveModel::EachValidator的各种验证类。使用自定义验证类能够使代码更加简洁,复用性更强。如:
validates :username, :availability => true, :legality => true, :username => true, ......

这里面就使用了三个自定义验证类:可用、合法、符合用户名规则。

1.3 workers/。在app/目录之下,内容是resque任务的定义类。

1.4 其它和项目相关的目录。比如在项目根目录下,我们加了一个monitor/目录,里面是resque和redis的监控脚本。因为监控脚本在概念上属于项目外层,所以放到根目录下面,不隶属于app/。

2、使用组件

2.1 rails 3.0.8。这个没什么可说的,用蜂蜜,川贝,桔梗,加上天山雪莲配制而成,实在是居家旅行、杀人灭口之必备良药。不过我们在3.0.8上吃了点苦头,丫把safe_buffer设置为不可改动,结果页面片段缓存的cache方法中的slice!触犯了这个禁条,网站首页直接挂掉。还好,发现这个问题是晚上10点,没有造成太多损失。3.0.9已经修正了这个大bug,请各位不必多虑。

2.2 mysql2。舍弃了mysql驱动,使用mysql2。不过要设置为'< 0.3.0',0.3版的mysql2是配合rails 3.1的。

2.3 ruby-oci8、activerecord-oracle_enhanced-adapter。连接公司oracle数据库取行情数据的。还需要安装oracle的instant client,把安装目录添加到/etc/ld.so.conf.d里,然后ldconfig。有想用oracle的可做参考。

2.4 nokogiri、yajl-ruby。正好项目中也要用到nokogiri,所以就干脆替代了rails自带的xml和json解析器。

2.5 authlogic、cancan。比较了一下authlogic和devise,感觉各有利弊。因为authlogic对于namespace的处理比较灵活,而且也利于第三方身份验证的扩展,比较适合我们的需求,所以最后选了authlogic。cancan对于不是很复杂的权限验证,也差不多够用了。更细粒度的权限系统,恐怕就得根据需求自己定制了。

2.6 acts_as_list、acts_as_state_machine、will_paginate。前两个不解释。will_paginate的rails3版本已经很久没更新了,不知道作者是恋爱了还是失业了。kaminari是个很好的替代,只是有些功能还没完善,是否可以完全替换will_paginate有待论证。

2.7 ckeditor、paperclip、rmagick。其实富文本编辑器已经有不少了,比ckeditor好的也不乏其数。不过具备相配合的成熟gem的,恐怕目前还只有ckeditor。如果不嫌麻烦,可以找个更好的编辑器,直接挂上去用,或者自己写gem挂到rails上。

2.8 redis-store、SystemTimer、mongoid。使用redis作为默认的rails缓存,SystemTimer是redis client等几个gem要求使用的,ruby 1.8.7的timeout不可靠,我见到的几个gem的作者都强烈建议使用SystemTimer。mongoid支持rails3,所以就没用mongo_mapper。mongoid配置简单,语法很不错,功能比较强大。

2.9 resque、resque-scheduler、eventmachine。研究过twitter当初做的starling和workling,勉强能用,但配置很复杂,而且很久不更新了,就始乱终弃之。resque套件另行开文,在此不多说。

2.10 formtastic。formtastic号称是语义表单,实际用起来还是挺不错的,erb上的代码简洁多了,学习曲线也不高,一看即会。而且formtastic扩展性非常好,我们修正了和ckeditor的接口,还自定义了日期选择(date_picker on jquery)、日期选择组(date_selects)和验证码(captcha)控件。

2.11 client_side_validations。这年头网站上没个客户端动态验证,出门都不好意思跟人家打招呼。它能够直接使用model中定义的验证规则,DRY得很。而且能够和formtastic无缝整合。另外也很好扩展,我们利用回调加上了动态验证时的绿对号红叉号的小图片。

2.12 capistrano、capistrano-ext。代码发布管理的。如果你有不同开发环境的十几台服务器需要依次发布代码,就知道这东西有什么用处了。同样,这部分将另行开文。

3、配置

虽然说“约定优于配置”,但也不能没配置。不过如果只要配置配置就能搞定,总比写代码好多了。

3.1 自定义配置。项目中要使用到一些自定义的配置,比如oracle数据库的地址、redis服务器地址等等,而且开发环境和产品环境的还不一样。我们在config/目录下放了一个configuration.yml,里面区分出不同的environment,各个env下写入各自的配置。rails初始化的时候读取该yml文件,把相应env的配置以hash存入全局变量。以后以此全局变量来取得配置值。

3.2 系统配置。rails3的系统配置大部分都在config/application.rb中。

3.2.1 config.autoload_paths里要加上#{config.root}/lib,3.0版本里不再自动加载lib/目录。

3.2.2 数据库存储时间的字段默认使用UTC的时区,显示这些字段时要加time_zone显式转换。如果你的项目确认一辈子都在天朝玩,不想加上啰里啰嗦的显式转换,可如此设置:
config.time_zone = 'Beijing'
config.active_record.default_timezone = :local


3.2.3 诸如ckeditor这样的组件要用到i18n,为了不出问题,最好还是显式指定项目的语言:
config.i18n.default_locale = 'zh-CN'
I18n.default_locale = 'zh-CN'


3.2.4 日志数据太多,可设置自动轮换,每周换一个新的文件:
config.logger = Logger.new(config.paths.log.first, 'weekly')


3.2.5 更换默认缓存和解析器:
config.cache_store = :redis_store, ‘redis://xx.xx.xx.xx:6379’
ActiveSupport::XmlMini.backend = 'Nokogiri'
ActiveSupport::JSON.backend = 'Yajl'


3.2.6 扩展css和js命名:
config.action_view.stylesheet_expansions[:formtastic] = %w(formtastic formtastic_changes)


4、相关问题

4.1 初始化顺序。功能模块和某些配置的代码,有些在config/application.rb中,有些在config/initializers目录下的.rb里,有些库在lib/下面,这就涉及到一个rails初始化顺序的问题。如果代码执行的顺序不对,就会得不到预期的效果,或者会出一些莫名其妙的问题。rails3启动时的初始化顺序大致如下:
config.ru -> config/environment.rb -> config/application.rb -> config/boot.rb -> rails framework -> bundle gems -> configs in config/application.rb -> alphabetical .rb files in config/initializers

以上顺序未做深入研究,不保证完全正确,权威指南请移步官方文档

4.2 sendfile。如果用nginx passenger做rails应用服务器,而且使用send_file或send_data来发送比如需要先身份验证等特殊需求的文件,需要在config/environments/下面的配置文件中设置:
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

否则send_file送出的文件大小为0。

4.3 本地化。需要翻译输出本地化文字的时候,尽量在config/locales/下面的相应文件里定义,这样能够精简erb或model的代码,职责也分得很清楚。目前我们在locales下面放了authlogic、formtastic、model中字段中文名和rails系统信息的中文翻译。

4.4 路由。rails3的routes语法改动比较大,而且写起来很自由。从项目管理的角度来说,有必要对routes的写法做统一的培训,使团队成员都真正理解routes的语法规则和适用环境,能统一使用最优写法的就尽量使用,实在不行再用其它写法解决。这样routes风格会比较统一。而作为反例,现在我们项目里的routes就是大家各显神通,什么样的写法都有,很不利于沟通和维护。

4.5 js框架。rails 3.0的默认js框架仍然是prototype,在jquery大行其道的今天,这个做法有点逆潮流而动。作为某些简单的js功能,用js generator是省时省力的做法,代码也干净。找了一个N年前就不更新的rails2的jquery rails,改了改使之适用于rails3,简单功能先凑合着用了。还好,3.1终于把默认js框架改成jquery了,当真是从善如流,幸甚至哉。

4.6 测试效率。即使在ubuntu平台上,跑rspec时rails所做的前期准备工作现在也延长到了好几秒钟,作为珍惜生命的开发人员,这几秒钟是难以忍受的。我们引入了spork作为测试的加速器,它会事先prefork出完整的测试环境,节省了初始化加载的时间。不过很不幸,我们现在做的rspec很少,所以在spork方面不做太多发言。

5、调优

在江湖的传说中,很多哥都会用“效率低下”来攻击rails。不过作为一个非计算密集型的项目,我们很少会注意到rails在代码执行上有瓶颈。但是在以下几个方面,我们还是感觉到了rails的某些不足,也尝试着做了一些优化。就效果来看,虽然没有数量级上的提升,但作为项目来说基本达到了要求。

5.1 应用初始化。rails3引入了rack作为底层架构,在架构层面上比rails2更为复杂,所以在应用的初始化时耗时相对较长。我们通过设置passenger_min_instances,提前多启动几个实例,减少用户访问时启动实例的时间。另外使用passenger_pre_start http://www.xxx.com/来初始化rails应用,减少初次访问的响应时间。不过比较郁闷的是,passenger_pre_start貌似效果并不是很明显,而且不支持touch restart.txt的重启,不知道以后会不会好一些。

5.2 虚拟机参数。即使是ree,ruby虚拟机的默认参数也基本上不满足普通应用的需求。我们参考了网上有关twitter和37signal的参数值,修改配置如下:
RUBY_HEAP_MIN_SLOTS=500000
RUBY_HEAP_SLOTS_INCREMENT=250000
RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
RUBY_GC_MALLOC_LIMIT=50000000
RUBY_HEAP_FREE_MIN=100000


5.3 erb解析。rails3的erb解析效率还是比较低的,听说默认的erb解析器erubis还是用c写的,不知道是我们的服务器不够强劲还是效率本来就如此。我们网站的首页大概有1000行erb,在使用了新的虚拟机参数之后,渲染时间大约在1秒钟左右。这个时间在用户体验上属于不可接受的范围。

我们把首页中渲染耗时较长的代码独立成片段文件,每个文件里面全部使用片段缓存机制。例如:
<% cache "recommend_#{$recommend_pageid}" do %>
……
<% end %>

其中$recommend_pageid是rails在初始化时计算的该片段文件的md5值,这样如果该片段文件有改动,缓存中就不存在这个新的key “recommend_xxxxxx”,rails将重新生成该片段的缓存。这个方法既可使用片段缓存提高渲染速度,又可实现片段文件改动时的缓存自动更新。

使用片段缓存之后,首页渲染时间降低到了200ms左右,基本满足了要求。当然我们还留了一部分页面代码没做缓存。作为一个懂人情讲政治的开发团队,要给自己留出足够的业绩提升空间以体现自身价值,并且给领导留出足够的命令空间以展现领导权威。这样下一次领导再让你进一步缩短首页访问时间时,双方可皆大欢喜。

6、rails on windows

首先我承认,windows确实很不适合rails开发,尤其是那个执行效率,生活在mac和ubuntu上的幸福的人儿是永远都体会不到的。不过,如果rails只是我生命中的一小部分,其它大部分事情我确实需要在windows上做,而且我还很不喜欢虚拟机,那就要研究在windows上开发rails了。本节内容仅是给喜欢windows的同学提供一点参考,ubuntu和mac控可鄙视加无视。

其实解决方案很简单,就是使用rubyinstaller,同时安装devkit。基于mingw32的这套系统应该还算不错,到目前为止,一般的需要编译的gem象mysql2、nokogiri等等都没问题,最多也就是加几个参数,便可编译安装。迄今只有SystemTimer因为使用到了linux的底层SIGALRM而无法安装,不过也可以想个办法绕过去即可,不影响实际使用。

我的操作系统是windows 7 sp1 ultimate x32,不要用x64,x64下的mysql2安装会有一些莫名其妙的问题。感觉x32位还是比x64方便,一般不会出兼容性问题。至于4G内存的限制,打个补丁就行了。
分享到:
评论
17 楼 wowpzp 2011-06-30  
请问楼主acts_as_list、acts_as_state_machine 应用在什么场合呢?有什么优点呢?谢谢!
16 楼 keer2345 2011-06-30  
rubyinstaller.org 是不是被墙了?打开不了页面,唉
15 楼 seamon 2011-06-27  
edokeh 写道
想知道LZ是如何部署的,不知道能不能再写一篇文章


部署的会写,可参见第一篇末尾的计划。不过什么时候写就不保准了,尽快吧。
14 楼 edokeh 2011-06-20  
想知道LZ是如何部署的,不知道能不能再写一篇文章
13 楼 richyzhang 2011-06-14  
rjs已经被抛弃了。rails3.0的时候已经很明显了。对新手来说,rjs还是很棒的,可以一点不懂js照样写出dhtml和ajax的应用。然而,随着越来越多的js高手的出现,rails团队自身对js的熟练,现在提倡直接写js。不过js虽然很强大,却难看了点,于是又搞出了coffeescript。

你说的replace_html基本上现在可以这么写

<%=link_to “say hello”, { :controller => “welcome”, :action => “say” }, :id => “ajax-load”, :remote => true, “data-type” => “html”%>

:id指明了要replace的内容,date-type说明返回的是一个html,:remote表示是一个ajax调用。
12 楼 seamon 2011-06-14  
QuakeWang 写道
引用

4.5 js框架。rails 3.0的默认js框架仍然是prototype,在jquery大行其道的今天,这个做法有点逆潮流而动。作为某些简单的js功能,用js generator是省时省力的做法,代码也干净。找了一个N年前就不更新的rails2的jquery rails,改了改使之适用于rails3,简单功能先凑合着用了。还好,3.1终于把默认js框架改成jquery了,当真是从善如流,幸甚至哉。

在3.1之前如果想用jquery的话,推荐
https://github.com/rails/jquery-ujs


我们现在用的就是ujs,不过ujs只是在表单等基础层面上替换为jquery,我说的是用jquery实现rjs,象replace_html这些简单的功能。

现在rails 3.1用的是jquery-rails,也兼容3.0。不过还是不支持rjs,官方的意思是rjs已经被踢出去了,默认不再支持。prototype和rjs被移到prototype-rails了。

jrails的作者问过jquery-rails的作者,问他们想不想加入jquery对rjs的支持,结果人家没鸟他,意思是3.1已彻底放弃rjs了。看来谁想在3.1继续用rjs又不想引入prototype,得寻求其它解决方案,或者自己搞一个jquery-rjs。
11 楼 edokeh 2011-06-13  
第一次听说client_side_validations,之前我看到最好的前端验证框架是jquery validate,不知道client_side_validations的功能与定制性究竟如何,但是能与后端公用一套校验规则,还是很吸引人的
10 楼 jn615 2011-06-12  
学习了, 不错的东东
9 楼 agile_boy 2011-06-12  
受教了,谢谢分享。
8 楼 QuakeWang 2011-06-11  
引用

4.5 js框架。rails 3.0的默认js框架仍然是prototype,在jquery大行其道的今天,这个做法有点逆潮流而动。作为某些简单的js功能,用js generator是省时省力的做法,代码也干净。找了一个N年前就不更新的rails2的jquery rails,改了改使之适用于rails3,简单功能先凑合着用了。还好,3.1终于把默认js框架改成jquery了,当真是从善如流,幸甚至哉。

在3.1之前如果想用jquery的话,推荐
https://github.com/rails/jquery-ujs
7 楼 活靶子 2011-06-11  
  感谢~感谢~
6 楼 seamon 2011-06-10  
Hooopo 写道
引用
不过我们在3.0.8上吃了点苦头,丫把safe_buffer设置为不可改动,结果页面片段缓存的cache方法中的slice!触犯了这个禁条,网站首页直接挂掉。还好,发现这个问题是晚上10点,没有造成太多损失。3.0.9已经修正了这个大bug,请各位不必多虑。

6月8号一天rails版本4连发就是fix这个问题。。
引用
Rails 3.0.9.rc1 has been released! 

Rails 2.3.12 has been released!

Rails 3.0.8 has been released!

Rails 3.1.0.rc2 has been released!

官方博客还更新了一篇文章:http://weblog.rubyonrails.org/2011/6/8/potential-xss-vulnerability-in-ruby-on-rails-applications


嗯,那篇文章是说为防止XSS攻击,所以才设置safe_buffer不允许修改,但是没说那个cache的bug。感觉这个bug还是比较严重的,凡是使用片段缓存的页面,肯定都要挂。比较严重的事故啊,测试不到位。

官方反应还是很快的,3.0.9rc1马上就修正了这个问题,改了actionpack里面的cache_helper.rb,没有直接output_buffer.slice!,而是先to_str了一下,然后slice!,再new成output_buffer。我也是参照官方的解决方案,直接把3.0.8的代码给改了,反正也用不了几天,估计3.0.9正式版很快就会发布。
5 楼 Hooopo 2011-06-10  
引用
不过我们在3.0.8上吃了点苦头,丫把safe_buffer设置为不可改动,结果页面片段缓存的cache方法中的slice!触犯了这个禁条,网站首页直接挂掉。还好,发现这个问题是晚上10点,没有造成太多损失。3.0.9已经修正了这个大bug,请各位不必多虑。

6月8号一天rails版本4连发就是fix这个问题。。
引用
Rails 3.0.9.rc1 has been released! 

Rails 2.3.12 has been released!

Rails 3.0.8 has been released!

Rails 3.1.0.rc2 has been released!

官方博客还更新了一篇文章:http://weblog.rubyonrails.org/2011/6/8/potential-xss-vulnerability-in-ruby-on-rails-applications
4 楼 wowpzp 2011-06-10  
学习了!感谢楼主!
3 楼 bluebu 2011-06-10  
希望rails3.1中的erb解析效率能够提高些。。。
2 楼 xinghu 2011-06-10  
如沐春风~~
大牛你好 !
1 楼 yang_kunlun 2011-06-10  
畅快啊, 楼主功力深厚啊

相关推荐

    Web开发敏捷之道-应用Rails进行敏捷Web开发 pdf

    《Web开发敏捷之道——应用Rails进行敏捷Web开发》是一本深度探讨如何利用Ruby on Rails框架进行高效、敏捷的Web应用程序开发的专业书籍。该书涵盖了从初学者到高级开发者所需的各种知识,旨在帮助读者掌握敏捷开发...

    Agile Web Development With Rails 3rdEdition Beta

    《敏捷Web开发与Rails》第三版Beta:深入解析与核心知识点 标题与描述明确指出了本书的主题——敏捷Web开发与Rails框架的结合。这是一部专为Rails 2版本设计的书籍,作者团队包括了Sam Ruby、Dave Thomas、David ...

    Ajax on Rails (PPT)

    ### Ajax on Rails 知识点解析 #### 一、引言 在当今的Web开发领域,Ajax技术已经成为了提升用户体验的重要手段之一。Rails作为一种高效、优雅的Web开发框架,与Ajax技术结合能够创造出功能强大且易于维护的应用...

    Agile Web Development with Rails

    综上所述,《敏捷Web开发与Rails》不仅提供了Rails框架的基础知识和实践经验,更重要的是传达了一种现代软件开发的理念——敏捷开发。无论是对于初学者还是经验丰富的开发者来说,这本书都是理解和掌握Rails框架不可...

    influxdb-rails-源码.rar

    《InfluxDB与Rails集成深度解析——以influxdb-rails源码为例》 InfluxDB,作为一款专为时间序列数据设计的高性能数据库,被广泛应用于监控、物联网、大数据分析等领域。Rails,作为Ruby on Rails框架的核心部分,...

    Agile Web Development with Rails for Rails 3.2

    - **Scrum和Kanban**:书中介绍了两种流行的敏捷项目管理框架——Scrum和Kanban的基本概念和实施步骤。 - **持续集成(CI)**:为了保证软件质量,书中讲解了如何设置持续集成环境,自动进行构建和测试。 - **版本控制...

    Agile Web Development with Rails, 4th Edition, Rails 3.1

    ### 敏捷Web开发与Rails 4th Edition (Rails 3.1)——全面解析 #### 核心知识点概述 《敏捷Web开发与Rails》第四版涵盖了最新的Rails 3.1版本,是一本旨在帮助开发者快速掌握Ruby on Rails框架的核心书籍。本书...

    Rails相关电子书汇总二

    2. **Ruby基础**:因为Rails是基于Ruby的,所以对Ruby的基础知识,如变量、数据类型、控制结构等的理解至关重要。 3. **ActiveRecord**:了解Rails中的ORM(对象关系映射)层,如何定义模型,以及如何与数据库进行...

    Crafting Rails Applications

    书中详细介绍了如何在实际项目中有效利用这些改进,帮助开发者更好地理解和掌握Rails 3的新特性。 - 例如,书中可能涵盖了如何使用Rails 3中的新API来优化数据库查询、如何利用新的路由系统来创建更加灵活的URL结构...

    Ruby For Rails(英文版)(清晰文字pdf)

    - **实战应用**:通过一个实际项目——在线音乐商店的开发过程,展示了如何将理论知识应用于实际的Rails开发中。这个例子覆盖了从需求分析到最终部署的整个流程。 - **源码解析**:最后,本书还介绍了一些探索Rails...

    [Web开发敏捷之道--应用rails源代码][5]txt

    【标题】:“Web开发敏捷之道--应用Rails源代码”是一个针对初学者的教程,通过深入理解Rails框架的源代码,帮助开发者提升Ruby编程技能。Rails是Ruby on Rails的简称,是一个开源的Web应用程序框架,遵循MVC(模型-...

    Pragmatic.Bookshelf.Agile.Web.Development.with.Rails.5

    书中提供的实战项目不仅帮助读者更好地理解和应用所学知识,同时也展示了 Rails 框架的强大之处。通过一个易于理解的例子,读者可以看到如何从零开始构建一个完整的 Web 应用程序,并了解整个过程中所涉及的技术栈和...

    Pragmatic Bookshelf - Agile Web Development with Rails (Final)

    - **数据库集成**:讨论了Rails与各种数据库的兼容性,如MySQL、PostgreSQL等,以及如何配置数据库连接,为实际项目开发打下基础。 #### 4. 持续学习与社区参与 - **保持更新**:强调了在快速发展的技术领域中,...

    rails框架指南.pdf

    然而,这种多样性也带来了挑战——选择过多可能导致决策困难,且并非每个开发者都能做出最适合项目需求的选择。 ### .NET平台的“一站式”解决方案 相比之下,.NET平台的开发环境,如Visual Studio .NET,提供了一...

    shopping_card_rails-源码.rar

    《购物车实现——深入解析"shopping_card_rails"源码》 在软件开发中,购物车功能是电子商务网站的核心组成部分,它允许用户选择商品并进行结算。本篇文章将深入探讨"shopping_card_rails"源码,揭示其在实现购物车...

    Agile Web Development with Rails (4th edition).pdf

    - **Scrum和Kanban**:本书介绍了两种流行的敏捷管理方法——Scrum和Kanban,并探讨了它们在Rails项目中的具体应用。 - **持续集成**:强调频繁地将代码合并到共享库中,以便快速发现并解决问题。 - **测试驱动开发...

    毕业设计——多用户博客系统.

    【标题解析】:“毕业设计——多用户博客系统”这一标题表明这是一个针对计算机科学与技术专业学生的毕业设计项目,主要涉及的是构建一个支持多个用户的博客平台。这个系统可能包含用户注册、登录、发布博客、评论、...

    Agile Web Development

    - **Agile Web Development**(敏捷Web开发)这一标题直接指出了本书的主要内容——使用敏捷开发方法进行Web项目的构建。这里提到的“敏捷”是一种项目管理和软件开发的方法论,强调迭代、快速响应变化以及持续交付...

Global site tag (gtag.js) - Google Analytics