almost 2 years ago

new or edit path helper? We can creating easy more path!

我們可能常常會需要在 view 裡面寫到 edit or new 的 link,這是我們在常見不過的一段判斷式了

some_project.html.erb
<% if @project.presnet? %>
    <%= link_to 'edit', edit_project_path(@project) %>
<% else %>
    <%= link_to 'new', new_project_path %>
<% end %>

然而我們認為更棒的作法,就是把這判斷式放進 helper 裡面,只為了讓 view 看起來更簡單一些,也許可以參照這篇 StackOverFlow

例如

some_helper.rb
def render_new_or_edit_project_path(project)
    if project.present?
      link_to 'edit', edit_project_path(project)
    else
      link_to 'new', new_project_path
    end
end

然後我們在頁面只要載入這個 helper 就好了,對吧?

some_project.html.erb
<%= render_new_or_edit_project_path(@project) %>

看起來一切完美,將 view 做了個 Refactor

but...轉折處就在這個 but

如果你未來繼續使用這樣的 Refactor 的方式,那麼 helper 裡面就會出現一堆

render_new_or_edit_xxxxxx_path 的這種鬼東西

或許你會認為可以把他用動態(dynamic)的方式生成,但得考慮到

  1. 如果遇到有 namespace 的 routes ?
  2. evalsend,是不是有 security issue 的問題? ,也許你會說使用 public_send,但畢竟這都是 ruby 的 meta-programming,對未來維護的時候,或許不是這麼好找尋?

那麼這個 helper 看起來又不是這麼好用了,變成只專門 for 某個頁面的方法,這樣真的是 refactor 嗎?

更好的方法

面對 new or edit 這個方法,我認為有更好的選擇

  • 使用 simple_form
  • 將 new or edit 交給 object 決定

我們可以統一把 path 交給某個 action 處理,個人偏好使用 newedit (如果你有更好的作法可以試試看自己設置的 action )

所以我們不需要花時間在判斷上面,只要連結一律導向 new_project_path

然後在 controller 裡面寫

def new
 @project = Project.find_by_id(params[:id]) || Project.new
end

如此一來,在你的 simple_form_for 裡面

some_form.html.erb
<% simple_form_for @project do |f| %>
...
<% end %>

他就能在 submit 時,自動選擇「new(新建)」或是「update(更新)」行為

因為這個自動選擇,是取決於你的 Object, Simple Form 會在將 object 傳送進來時,決定你的 action 以及 method

我們在 simple form 傳進去的 object ,在這裡定義為 record

form_helper.rb
action = record.respond_to?(:persisted?) && record.persisted? ? :edit : :new

也因為在這裡就做好選擇,所以一切是這麼智能,如果你想更了解,請詳見 simple form 的 source code 是如何因 object 決定行為

補充一下,如何知道這個 object 是已經存在?或是剛 new 出來的?

Project.new.new_record? # true

Project.new.persisted? # false


# 假定數據id為1的 project 存在的情況


Project.find(1).new_record? # false

Project.find(1).persisted? # true

如此一來,就不用寫這麼多的 new_or_edit_path 的 helper 啦!

 
almost 2 years ago

精進C群

A組組長 MengjunGuo - 精进练习一个月总结

历时一个月的精进练习已经落下帷幕,感觉这个月的投入精力、时间和注意力比之前正式学习时要多很多。精进一个月比最开始的三个月更主动、积极和自觉,自己所感受到的深度也完全不一样。

匆匆忙忙一个月,总算是赶在最后一天把所有布置的任务都完成了。

B組組長 叶同學 - [学习笔记]一个月的精进让我充实许多

在精进的这一个月时间里,让自己的生活更加充实,编程已经逐渐纳入到自己的日常生活之中,甚至已经有了一种依赖心理,如果哪天发现没有敲代码会觉得这一天不够完美,哪怕自己Github上今天只推一个commit有了很浅的“小绿点”也会让自己心里舒服一些。

精進B群

小組長 李同學 - 精进群总结

其实参加全栈营真的收获了很多编程以外的东西,三言两语也还说不清。

在精进群中其实最大的收获就是让自己保持学习的习惯吧,毕竟学习能力是很重要的竞争力。

参加魔改大赛、精进群,其实都是给自己动力去学习,但两三个月的时间是远远不够的。在这之后一定要保持住学习的劲头、习惯,甚至成为一个终身学习者。

楊同學 yangxiaodan - 精进,向前进

这一个月来,沉浸在代码的世界里,一步一步地拾阶而上,已然成了一种习惯。Nic老师说,“代码需要时间来浸。”我晓得时间的力量,所有头顶光环的大神都不是一蹴而就的。

如果没有沉浸在这样的学习群里一个人闭门造车,效果必然是大打折扣的。偷懒是人的天性,大多数人都需要外在环境的激励。在精进班里,看着优秀小伙伴们一个劲地往前冲,被消磨的斗志又重新被点燃了。

周同學 ZSMHY - 精进一月的总结

在精进群小组学习的这一个月时间里,我感受到了小伙伴们的强大而充满热情的学习氛围。群里每天都固定提交学习进度和成果,既是压力也是学习动力,还有小组组长无形之中的督促。两位组长除了每天自己的作业练习,还细致认真的把每个小伙伴的练习进度进行表格登记,记录了大家整体的学习情况,方便大家复盘,真的非常感谢他们。

李同學 - 精進群一個月的心得

本來覺得兩個星期,這樣好像沒學到什麼東西,但這樣強迫自己回想這兩個禮拜做了什麼,原來在不知不覺地練習中,學會了不少知識和框架(雖然現在要我自己提取還是做不到)
是對成為可以被使用的工程師還有一段很長的路要走,我也沒有什麼很大的願望,只是希望在學了這全棧營以後,能像Nic助教一樣,能用寫程式來幫助周圍的人,解決他們遇到的問題,像是做出訂午餐9453或是區鍊塊貨幣的錢包之類的工具,這讓我當初在直播前面聽到很興奮,不是虛無縹緲的東西,是實際上可以幫助到人的東西

何同學 Smilingjun - 精进群心得

进群后开始进行把jdstore重新做一遍就让我收获很大,也可以说因为这件事情,我成为了一个会主动去把以前做过的东西再做一次的人,后来听到(忘记谁了囧)不断重新优化与构建自己代码的过程就是一个成长的过程。通过这次回顾,收获颇丰。

邱同學 qiuchengxiao - 精进总结

为期一个月的精进营就要结束了,突然觉得时间真的过的好快,想到要和自己奋斗一个月的小伙伴们分离真的是很舍不得,因为这已变成了我的习惯。在这一个月里自己又成长了不少,编程也精进了不少,真的很感谢你们,全栈营,插袋老师,nic 老师,各位助教,当然还有营里勤劳的叶达明队长和可爱的战友们。

马同學 maxiaojing - 我在精进群里一个月的收获总结

进了精进群之后,大家就好像一个大家庭似的,有组长和组员们共同督促练习,知道自己并不是孤独的一个人在奋斗,出了错有组员们帮助,集思广益。
对于现在的我而言,虽然还是不能脱离教材做输出练习,但我还会再继续复盘以前做过的章节,反复练习,出了错可以在谷歌上或者论坛里找答案,像拼图一样,一步一步的继续走,不会放弃。

郭同學 - 精进4周总结

四周的时间很快就结束了。在这四周里与同学们一起打卡,学作业,真的很有趣。比自己写作业有趣多了,让我想起了笑来老师说的学习就是社交。
其实并不是自己一个就不愿意学习,在平时自己也会认真学习相关的知识,但是总是觉得只有自己一个人。做的事情就没有那么有趣了。
加入精进组之后,每天看见有很多与我一样的同学,每天都在打卡,写作业。这时终于觉得不是一个人在战斗了。
当然,在这四周里,成长最多的,还是对于编程的理解。可以明显的感觉到,自己知道的变多了。

曾同學 kinglinxinsen - 一个月精进总结

时间过得好快,一个月的精进学习已经结束,通过这一个月的学习,虽然个人进度还是没跟上,但总体上还是有很大的收获。

周同學 kingzhoujin - 精进替代懒惰

希望精进营形式能够举办下去,并且可以授权各地学习小组进行,最好由全栈营官方出具精进营训练的官方指引,将组织权限下放到各地meetup小组,举行线下meetup精进,这样效果应该会更好,全栈营助教只需监控各地进度并给予指导就好。
虽然精进营结束,之后我也还是会坚持继续精进,一切才刚刚开始。

梁同學 精进群心得

这次参加精进群最大的收获是目标设立和拆解。这在构建反馈方面有很大的作用。反观之前自己做练习的时候,根本没有这个概念。虽然教材上面明明写着“建议完成时间”,却一直不当一回事。你看,这又是一个活生生的没有放下傲慢的例子。
精进的小套路是:设立目标,分解目标,看反馈再做调整,一直重复到效率提升为之前的100%!

精进群已告一段落,路还要继续走,精进不能停。

孟同學 - 精进群心得

精进组已经结业,但是成长还会继续。自己因为精进群发生的实质性小改变
1⃣️自己设定目标,并达成目标这样的任务行动模式。
2⃣️会主动的去在要求之外把知识进行重复。
3⃣️让我对加入社群产生出刚需。

陈同學 - 一个月精进总结

其实很庆幸自己参加了精进练习,没有在比赛之后就完全放弃学习了,新课程能学到的知识真的不亚于大赛能学到的,现在觉得自己以前那种比赛结束了全栈营的学习就结束了的想法大错特错,后续还是要继续课程的学习,反复刻意练习。

吕同學 - 精进,重在坚(上)持(瘾)

一个月的精进群训练今天结束了。回顾这一个月,发现自己的练习量比大赛期间还要多!在全栈营之后还能保有这份对编程的热情,想想还是挺开心的!

身边很多全栈营朋友在大赛结束后就停止编程学习了。很高兴,我是仍在前行的那一个。感谢精进群的老师、组长和小伙伴们的督促和鼓励,也感谢自己坚持每天提交作业,坚持对各种小功能做提取练习,坚持每一个作业都在新的专案中作迁移。虽然也有很多做得不好的地方,但这个月自己的进步还是很大的。精进训练结束,但编程学习仍在继续。希望,在今年年底全栈营全部课程结束之时,我是能跑到终点的那一个。

丁同學 - 精进群一个月总结

希望下一期精进群的同学,好好做以下,里面的内容如果能好好理解运用的话,真的会收益匪浅,自己也是因为时间原因,这块的教材练的还不够,还满可惜的。

叶同學 - [学习笔记]一个月的精进让我充实许多

在精进的这一个月时间里,让自己的生活更加充实,编程已经逐渐纳入到自己的日常生活之中,甚至已经有了一种依赖心理,如果哪天发现没有敲代码会觉得这一天不够完美,哪怕自己Github上今天只推一个commit有了很浅的“小绿点”也会让自己心里舒服一些。

舒同學 - 精进学习总结

精进学习已经一个月了,时间过的飞快,收获也是很大的,前两周共完成Joblisting 及JDStore,rails百宝箱第二集,第三集部分的练习。后两周完成了rails百宝箱第三集,SQL入门,rails百宝箱第四集,自动化测试,编程语言第一集以及我自己项目的用户故事,landinpage和onborading

吕同學 - 精进群 ORID

不管多忙,基础学习的时间不能停.

赵同學 - 精进营总结

由于正式的课程已经结束,感觉大家多少有点放松,很难想象一个月做这么多等东西。通过复盘招聘网站和购物网站,进一步理解了其中等深层内涵,有些我们以前做的时候不懂等东西,通过这次等练习也基本都弄懂了。

姜同學 - 精进组一月总结

这一个月的持续学习,本来自己一个人是很不容易做到。每天保证四个小时以上,并且持续的做下去的。是因为群里的小伙伴们,每天都汇报着自己的进度,并且互相鼓励着,有了问题在一起讨论形成的氛围,激励着自己要按时的做完今天的进度。比起前几个月自己一个人做的感觉好的太多了。因为多了一个监督自己的地方,让自己可以不但可以内激励,还有外部的监督。保证了自己每天都在练习编程,投入时间持续的学习。

颜同學 - 精进群结业总结

如果不加入精进群,我可能会拖延症好久才回进行提取练习,因为真的让大脑反向提取内容在刚开始是非常困难的,但是作业要求再加上同学们的分享,我逼迫自己把功能分开提取会议,试着替换一些数据,不完全按照教材提取,发现会更加直观的感受各个功能的实际意义。这些东西如果不自己提取是无法体会的。

李同學 - 知识创造财富——精进群30天总结

精进群使我可以用正确的方法去做正确的事情,光光这一点就已经是很大的收获了。

总体来说,这次参加精进群,让我找到了全职在家应有的学习状态,让我离用编程解决重复性劳动这个终极目标又进了一步,也消除了我在独自成长上的孤独感。所以其他同学们,心动不如行动,赶紧报名下一批吧。我们要相信,知识是可以创造财富的!

周同學 - 学习,就要对自己狠点

这个月以来,面对精进群布置的任务确实比较高难度,但是,复盘是不能跳过的坎,如果畏惧,看到这样大的任务就吓到了,不正视不去做,那么很难由小白跳出来,很难“破局”。

petersngg - 7月小结

当投入到一件事中,时间流逝的特别快。7月就过得特别快。

一个月前,我加入ROR精进群,跟12位队友持续学习,相互监督,相互对比。现在想起来,当初若不是加入这个群,7月份也不会取得下面这么多的成绩。

张同學 - 精进c群一个月总结

一个月前的今天7月1日加入了精进c群,回顾这一个月。当初参加,踌躇满志,现在心里空落落。究其原因,就是这一个月没有按照群要求完成作业。

 
almost 2 years ago

唐同學 - 全栈营求职群收获总结

Nic老师用自己经过实战的宝贵经验,建设了一个贴近实战的模拟环境。有的放矢的用“套路”锻炼了我们,尽可能地引领我们,少走了很多弯路。

来到求职群的初衷就是求虐求鞭策的,一个月下来,无论从心态和自驱力上都得到了一次改进。

最大的收获就是注意力的收敛和专注度的提高。外面的世界诚然精彩,但既然选择了程序这条道路,那么在还没有成长到一定阶段时,就要果断放弃很多占用注意力的事物,好钢用在刀刃上。

不仅跟进了群内的作业,还因为通过作业认识到了自己的不足之处,激励并提高了每日课程学习的时间占比。

江同學 - 求职群第十一次作业心得体会

我深深地感到参加这次求职群达到了我预想的目的,NIC老师全方位地从个人简历的准备,面试的自我介绍,面试题的准备到笔试题的练习实作,对应聘公司的产品观察及建议,到更多实作项目的要求,设计了重重关卡,可以说如果这些关都能够轻松闯过的同学我觉得现在就能找到工作。

这次的求职群指导,极大地锻炼了我们的求职能力,虽然我现在的水平自己还很不满意,但我知道接下来应该主要补全哪些方面的知识,这个非常重要。更为关键的是确实要开始行动了,要开始准备发简历,光靠在屋里闭门造车肯定 不行,必须要有行动,要勇敢地去接受面试笔试的挑战!

衷心祝愿在求职群的27个同学(包括我自己)都能找到自己想要的编程工作,祝我们走过的每一步都算数!

黃同學 - 求职群心得总结

我以前从没写过简历,说到求职面试,就感觉是一道自己跨不过的坎,这一个月的求职面试群经历真的让我感觉收获很多,在nic老师的帮助下,我写了第一份简历,并经过两次修改和一次口语表述,感觉写简历其实并没有自己想的那么恐怖,按着套路来,参考优秀的个人简历,然后把自己的个人经历套上去,再一步步完善。

祁同學 - 在求职的道路上,一切才刚刚开始

我发现Nic老师的这个作业也非常好,可以通过对专案的二次梳理,总结出自己学到了什么内容,学到新功能,需要补充的知识点,对模糊的内容进一步的探究,达到做这个专案的经验值。

李同學 - 全栈求职群月结

Nic老师每期任务完成后都会把大家的答案公布在群里,大家可以互相浏览、学习,发现群里的小伙伴们的作业质量都非常高,对我启发也很大,比如对面试公司产品提建议的那次印象很深,其实这是要打破固有思维、用更客观的角度去看待产品才能提出更高质量建议的题目

張同學 - 我在求职群的精进之路

参加求职群之前,我自己写的简历就是简单粗暴的罗列所有个人信息,毫无重点,真的可以直接放进简历黑客里当反面教材。而我在nic老师的指导,并使用过简历黑客的服务后,才认识到原来可以用套路来完成简历的。

nic老师很nice的给每一位小伙伴提出了各自简历中的建议。我可以从里面好的方面借鉴学习,同时避免那些不是特别合适的简历方式,这样的学习方式特别的高效。

陳同學 - 对于求职群一个月经历的总结

在我之前的认识里,简历的撰写并没有什么技巧可寻。不就是从网上下载一个模板,然后把自己的情况填进去,有什么写什么,就可以了。
看了求职指南以及老师给的简历范本之后,才意识到原来这里面还有这么多技巧。各个内容板块的顺序侧重点如果安排不当,很可能就被刷掉。

吉同學 - 我在求职群一个月的收获总结

自我介绍录音这个作业相当有趣,一直以为,自我介绍,就是随便两句就搞定,甚至一度觉得面试官如果在拿着你的简历的时候,还要你做自我介绍,那这个面试官就是SB.... 也是在看了一些帖子,又去询问了有人资经历的朋友,才知道,这个环节是有它存在的意义的

再着,自己给自己录音,由于我想要尽量模拟还原面试的场景,所以,选择先背下来,不背不知道,还是,很要下点功夫,也是在这个过程中,让我突然感觉,简历、面试,的准备工作真的是很多很细,并不想以前以为的那样随意、简单。

劉同學 - 全栈营Nic老师求职群心得

Nic老师的求职群目标明确,层次感强。难度逐渐增加,不断的实作面试实战中的各个环节。
自己之前对简历的撰写存在一些恐惧,因为只有目前的自学经验,不会的太多太多,求职群里,Nic老师给大家比较明确的套路

荷同學 - 我在求职群一个月的收获总结

我知道这是一个和大家一起学习与互动的难得机会!而且我也很欣赏Nic助教的沟通方式。总是很正向温暖的鼓励同学们。也慷慨地与同学们分享自己所知所学。当Nic助教一建立完成求职群组,我就確信这个七月我会过的非常扎实有收获!
七月已经到了尾声,我要再次感谢持续用心经营求职群的尼克助教,以及各位努力的同学们,我相信在程序员的这条路途上持續奮鬥著.
就像是尼克助教所说的:一切才刚开始。

邢同學 - 我在求职群一个月的收获总结

令我始料未及的是,在求职群中一个月的锻炼,自己的技术、认知和心态都有了很大的改变。

楊同學 - 找工作的正确姿势——求职群ORID总结与实录

一句话总结,你把时间撒在这里了,就会有收获!!!

所以能看到,找工作就是:技能占大一部分,拿出完整的作品的能力,但只是一大部分,还有对目标公司的了解,对目标公司的重视程度,写简历,改简历,准备自我介绍,给人讲故事,体现自己都做了什么,不断重复重复再重复,直到成功。

沙同學 - 求职营总结

一转眼一个月的时间匆匆而逝,在这一个月的时间里,辛亏有了 Nick 老师的帮助,自己才能在紧张的做research 的同时,也没有完全将 ror 扔下。

孔同學 - 20170731_ORID日志

改变了我对“求职”这件事的认知。

王同學 - 我在求职群一个月的收获总结

这样看来这个月我还真做了不少事呢!我最大的收获就是思维上的转变,因为Nic老师想让我们学习到的,肯定不是做一个任务就能获得的,他的思路方式、如何解决问题的方式和练习方法是最重要的,在接下来的练习和实践中,我都会采用Nic老师教的方法,不记得就回头复习,再出发,再复习,如此往复!幸运的是我们的求职群永远不会解散,并且以后还可以在群里分享自己的面试经验和提出困惑。我在墙上一直贴着笑来老师的话:用正确的方法做正确的事情,你一定会变得更好!若长期持续用正确的方法做正确的事情,你的未来一定会很伟大!

费同學 - 7月总结

其实一切才刚刚开始,只有通过不断的实际面试才能学到新的技术、改变错误的观念和想法。

熊同學 - 求职群收获总结

通过这几个作业让自己看到了很多非科班出身的全栈小伙伴的一个弱点(通病),在进行正式的面试前,建议大家都夯实下自己的编程基础知识,这是最容易拿分同时有最容易忽略的部分。

陳同學 - 我在求职群修炼一个月的收获总结

面试其实是个查缺补漏的过程,可以发现自己以前遗漏的知识点,为下一次面试做准备

罗同學 - 求职营感想

不知不觉中一个月过去了,全栈营的求职群也到了最后一次作业。想当初刚进群的时候带着茫然,带着焦虑,带着对未来的不确定加入的求职群,到现在的虽然仍然不确定,但是心中却不像原来那么的焦虑和无助。谢谢大家的陪伴,在这一个月里我才对于简历对于求职有了清楚的了解。

忽同學 - 求职群心得

知易行难,贵在坚持,通过这一次的求职群的一系列任务,我们通过设定一个任务目标,而去进行各种各样的尝试,完成各式各样的任务。

王同學 - 求职群中的一个月

反反复复的一个月,也很充实的一个月,在求职群中的这一个月,完成了十个与众不同的任务。从简单到困难,做出了一些很有趣的小玩具,同时也在帮单位做一些小项目,学以致用的感觉还是挺好的,毕竟没有白费功夫去学习。
其实我感觉最好的学习在于总结,老师们一直要求我们写心得,也是在培养一种学习方式。在这最热的一个月,我完成了求职群中的作业,以后也不知道有没有机会会有老师留作业,然后在每个接近临近交作业的晚上,拼命做作业不想被拉下,生活不易,且行且珍惜,愿在这个群中我们还是可以一起讨论问题,虽然在不同地方,但我们学过同样的东西。

凌同學 - 我的全栈求职群复盘

转眼在求职群已经学习了一个多月的时间,在nic的带领下,完成了十次作业,掌握了很多求职的技巧。

王同學 - 求职,在路上

一个月的求职学习算是告一段落了,没有nic大神的任务布置,接下来的就是自己见招拆招,必要的时候也可以在群里讨论,请教nic老师和其他大神、同学们。
我很幸运参加了这次培训,感谢全栈营,感谢nic老师。

張同學 - 在求职群收获的一些原则

时间总是在回顾的时候,才显得飞快。这是全栈营的最后倒数第二次作业了(最后一次我觉得应该是在10/1前获得offer),下面是我在求职群一个月时间的收获,我把学到的正确的做事方法,总结成了一些原则。

肖同學 - 7/30 我在求职群一个月的收获总结

在做求职群的作业的时候越来越不怕换工作了一样,一切都可以学一切都可以通过训练得到提高,不会的就学就好了。

思同學 - 求职群一月总结

 
almost 2 years ago

製作微信 GIF 貼圖吧

限制

微信GIF要注意只能上傳 1MB 的圖檔

Step 1 :素材準備

  • 五至七秒左右的影片,不宜過長
  • 想一個可以加在影片上的文字

Step 2 :剪輯影片

這邊我是使用 Mac OSX 自帶的 imovie 剪輯,加上字幕
手機或移動端推薦「小影」APP

Step 3 :將影片轉存至GIF(video to gif)

這邊我使用這套網站進行出圖XD

https://ezgif.com/video-to-gif

因為他可以把畫質跟格數調至最低(不調低很難達到 1MB 以下的限制)

上傳影片後,如圖所示設定

如果還是超過 1MB 最後的絕招就是進行 GIF 壓縮

Step 4 :壓縮GIF圖檔

推薦使用 compressor.io

實測壓縮能力最好,基本上到這邊都能壓到 1 MB 以下,如果真的還是超過,基本上就是影片畫質太好或時間太長,需要回到第一步將影片在降低畫質跟時間

Step 5 :上傳


新增為貼圖吧!

 
almost 2 years ago

在 Rails model 裡面,我們很常會定義所謂數據的「狀態」,比方說一個請假系統,光請假這個數據,可能他的狀態就有「待審核」、「已審核」、「已退回」、「已取消」。

雖然 Mysql 裡面也有 Enum 屬性可以設置,例如

CREATE TABLE person(
    name VARCHAR(255),
    gender ENUM('Male', 'Female')
);

既然一般資料庫都有 enum 屬性可以用,那為何我們很少知道有人這樣開發,其最大的問題在於這個 enum 會在建立這張表單時就塵埃落定,一旦後期需要增加一個狀態就意味著要在加一個字段,而且各類型的數據庫對於 enum 的方式處理不盡相同,會對 ORM 造成不小的麻煩,而 Rails 就除去了這個麻煩,讓數據庫只要單純的儲存 integer,並在 model 中來維護這些關係,並不直接使用數據庫的 enum,

在該 model 裡面,我們可以使用Constant(常數)去定義一個狀態的初始值

class LeaveEvent < ApplicationRecord
  STATUS = %i(pending approved rejected canceled).freeze
end

然後在 migration 生成數據時,切記狀態 default 值一定要設定「pending」

class CreateLeaveEvents < ActiveRecord::Migration[5.0]
  def change
    create_table :leave_events do |t|
      ...
      t.string :status, default: "pending"
      ...
    end
  end
end

這樣的作法是多數人在設定狀態會有的寫法,不過 Rails 在 4.1 的部分就針對了這樣常見的設定做了一個更棒的設置

ActiveRecord::Enum 的 Module

官方说明:

Declare an enum attribute where the values map to integers in the database, but can be queried by name.

如此一來,就可以用 enum 解決這個狀態設置的場景,更棒的是在資料庫裡面只需要儲存 integer 可以取代原本的 string

By the way 數據欄位型別也是會影響速度

Boolean > Integer > String > Date > Datetime

以請假系統來說,我們可以如此應用 Enum, 詳細參見官方文檔

先在 model 裡面宣告

class LeaveEvent < ActiveRecord::Base
  enum status: { pending: 0, approved: 1 ,rejected: 2, canceled: 3 }
  # or

  enum status: [ :pending, :approved, :rejected, :canceled ]
end

宣告後,會幫你生出這些方法

leave_event.approved! # 將狀態改寫為 approved
leave_event.approved? # 檢查該狀態是否 approved

leave_event.status     # => "approved" 輸出 String
leave_event[:status]   # => "approved" 輸出 String(Rails 5 Feature)

leave_event.status = 1            # => "approved"
leave_event.status = 'approved'   # => "approved"
leave_event.status = :approved    # => "approved" 
賦值時,以上三者等價

# 自動添加 Scope
LeaveEvent.approved    # 等價於 LeaveEvent.where(status: 1)

# 自動添加 statuses(status 的複數) 的 Hash
LeaveEvent.statuses # => { "pending" => 0, "approved" => 1, "rejected" => 2, "canceled" => 3 }

這邊值得注意的一點是,通常這些狀態設定,幾乎都不會更動順序,一旦更動順序可能就會導致災難發生

比方說

# 原先定義的順序

enum status: [:temporary, :active, :deleted]
# 修改之後

enum status: [:temporary, :active, :waiting, :deleted]
# 如果這樣修改的話,以前的 deleted 的數據修改後就變成 waiting了

而且上述的例子中,容易讓人混淆順序,所以並不推薦使用

enum status: [:temporary, :active, :deleted]

而建議有良心的寫 code

{ temporary: 1, active: 2, deleted: 3 }

也因為 enum 會自帶一些 scope ,這部份也要注意有沒有與原先自己設定的 scope 衝突,像是如果使用 enum status: { none: 0, active: 1, deleted: 2}

那麼 Rails 自帶的 none 就會被覆蓋了哦

參考資源

 
almost 2 years ago

一般工程師 code 寫久了都會養出自己的專屬配置,甚至整理相關的 dotfile

Alias 這更是必備的設定啊,工程師通常都不喜歡一直打重複又冗長的指令,做成自己能懂得縮寫是絕對要的

不過在這之前,除了客製化的 alaias ,如果你的 shell 是用 zsh ,那別忘記 oh-my-zsh 裡面有更多 magic 的配置哦,在這邊我就分享幾個常用的 alias 吧!

ggpush => git push origin git_current_branch
ggpull => git pull origin git_current_branch
(可以 推/拉 currnet branch 超方便!)

gco => git checkout
組合技 gco -b develop

ga => git add
gaa => git add .
gst => git status

可以查看 ~/.oh-my-zsh/plugins/git/git.plugin.zsh 了解更多 alias

 
almost 2 years ago

常見更新數據狀態的作法

一般來說,除了狀態機(AASM)變更狀態以外,有一種情況是針對這筆資料進行狀態變更,通常的設計是這樣子的,有一個按鈕,按下去之後觸發功能。

  1. 按鈕按下去,找到 route
  2. route 進到該對應的 controller action
  3. action 內觸發 ActiveRecord 裡的 method 進行數據 update

比方說 user 可以創建很多 group,但我想要讓 group 在畫面顯示的時候可以由後台進行控制,公開或是隱藏

所以這時候就會出現

groups_controller.rb
def publish
  @group.publish!
end

def hide
  @group.hide!
end
config/routes.rb
resources :groups do
  member do
    post :publish
    post :hide
  end
end

那麼如果我要控制這筆 group 的 position 呢?比方說往上一筆,往下一筆
你有可能會使用到acts_as_list這隻 gem 來完成。

那麼我的 controller 裡面豈不是又要加入這兩個 action 變成

groups_controller.rb
def publish
  @group.publish!
end

def hide
  @group.hide!
end

def move_up
  @group.move_higher # acts_as_list 裡面的 helper method

end

def move_down
  @group.move_lower # acts_as_list 裡面的 helper method

end

然而 routes 也得變成這樣...

config/routes.rb
resources :groups do
  member do
    post :publish
    post :hide
    post :move_up
    post :move_down
  end
end

如果我在來個將 position 置頂、置底呢

move_top, move_bottom ?

沒完沒了的佔用了很多 controller 中的 action 還有其 routes

其實在上述的例子,一般新手或是以前的我都會這樣寫,那麼這個東西既不好維護,又容易讓程式碼越來越長,卻只為了更新某一筆資料的狀態或是位置?

有沒有更好的作法?

我認為這些單純更新數據的行為,在 HTTP 動詞裡面應該用 patch 而不是 post,這個 Rails guide 裡面有提到。

所以我的想法是,把所有這樣的行為,透過傳遞 params 的方式來做選擇,而這個最適合做選擇的地方,就是 CRUD 裡面的 update ,我認為既符合原意,又不浪費 action 與 routes。

首先將你的觸發連結,全部導向 update action

利用 link_to,在 path 中夾帶 value,並且打 patch 出去

app/views/groups/index.html.erb
<%= link_to "公開", group_path(@group, status: "public"), method: :patch %>

<%= link_to "隱藏", group_path(@group, status: "hide"), method: :patch %>

在將 controller 裡的 update 改寫一下

groups_controller.rb
def update
status = params[:status].nil? ? "update" : params[:status]

  success =
   case status
   when "update"
     @group.update(group_params)
   when "publish"
     @group.publish!
   when "hide"
     @group.hide!
   else
     false
   end
 
  if success
    flash[:notice] = "#{@group}更新成功。"
    redirect_to groups_path
  else
    render :edit
  end
end

如此一來,你只要遵循這樣的設計模式,就可以減少 controller action 與 routes 的濫用

  1. 於連結中傳入 status 參數(publish/hide/move_up/move_down/...),並使用 HTTP 中 patch 動詞
  2. 於 controller 中的 update action 裡面設定 status 只接受何種狀態(如上述程式碼中的 case when )

如此一來,就不會因為變更狀態而寫了一堆 routes 與 controller action 了

你只需要維護 update 中的部分,畢竟變更狀態,就是 update 一筆資料中的相關欄位嘛

喔對,你的 routes 裡就只要一行

config/routes.rb
resources :groups

就是這麼的乾淨!

 
almost 2 years ago

How to split routes.rb into smaller parts?

在 Rails 開發上, route(路由)就像總機小姐,可以清楚的幫你承接到業務承辦人員, Routing 就是替你的頁面指路,經過 Controller Action 後呈現你想要的頁面。

在 Ruby on Rails 開發應用上, config/routes 這隻檔案會隨著程式碼日積月累的成長而變得更肥大,這會使開發人員更難以維護,也會在搜尋具體路徑變得越來越困難,當使用者頁面、登陸頁、後台、API…等路由全都攪和在一起,那是非常惱人的事情。

參考如下:

ActionController::Routing::Routes.draw do
  root to: "home#index"
  get "/about
  get "/login" => "application#login"


  namespace :api do
    #nested resources

  end

  namespace :admin do
    #nested resources

  end

  namespace :messages do
    #nested resources

  end

  namespace :orders do
    #nested resources

  end
end

Rails 3

如果你的應用程序在 Rails 版本 3,可以嘗試以下的解法

config.paths["config/routes"] += Dir[Rails.root.join('config/routes/*.rb’)]

想控制的更清楚一些,可以指定引入的檔名

config.paths["config/routes"] = %w(
      config/routes/messages.rb
      config/routes/orders.rb
      config/routes/admin.rb
      config/routes/api.rb
      config/routes.rb
    ).map { |relative_path| Rails.root.join(relative_path) }

Raisl 4

不過在 Rails 4 之後,如果你利用了上述的寫法嘗試解決,會拋出異常(throw an exception),因為在 Rails 4 之後的版本裡, Rails::Engine 並不存在這個 key ['config/routes']

那麼最佳的解法,是可以共存 Rails 3 & 4 & 5的

看以下範例 code

YourApplication::Application.routes.draw do

def draw(routes_name)
    instance_eval(File.read(Rails.root.join("config/routes/#{routes_name}.rb")))
end

  draw :messages
  draw :orders
  draw :api
  draw :admin

  root to: "home#index"
  get "/about
  get "/login" => "application#login" 


end

這樣你就可以在 config/routes/api.rb 只放關於 api 的 routes

config/routes/api.rb
  namespace :api do
    #nested resources

  end

可以只在 config/routes/admin.rb 只放關於後台權限相關的 routes

config/routes/admin.rb
  namespace :admin do
    #nested resources

  end
project
└─── config
│   │   routes.rb
│   │
│   └─── routes
│       │   api.rb
│       │   admin.rb
│       │   ...

是不是看起來好多了?

將同一種類型的路由整理起像 component 來使用,除了好維護,也容易進行找查相關路徑。

其原理是 ActionDispatch::Routing 允許我們在裡面加入一個新的方法來使用,這有助於我們加載相關路徑。

參考資源:
How to split routes.rb into smaller parts?

 
almost 2 years ago

一般 Rails 開發久一些的工程師,都會對還要額外開一個 terminal 來跑 localhost:3000 這件事情來得厭煩

尤其容易遇到如果同時開發兩個專案以上,要不時的切換來切換去,或是在開一個port 來執行 rails s -p 3001 ,同時也會佔用一個 terminal ,並且也沒有一個容易記一些的域名,比方說 nic-repo.dev

Pow 這個玩意兒就是來解決這些工程師的困擾,當你訪問該開發用的 domain 時會直接啟動 server ,並且在預設的 timeout 過後會自動 kill server 運行。

也可以安裝相對應的 gem install powder,就可以直接執行重啟指令

powder restart

而不用原本的

touch tmp/restart.txt

Pow 安裝方法

進入 Pow 官方網站

依照說明,執行安裝指令

curl get.pow.cx | sh

接下來切換到 .pow 目錄

cd ~/.pow

然後對你想要做開發域名設定的專案做個 sync

ln -s /path/to/myapp

例如,我希望能訪問 nic-repo.dev 來進行開發我的 nic-repo 的話

ln -s ~/projects/nic-repo nic-repo

就可以順利訪問 http://nic-repo.dev 進行開發了哦

查看 log

Rails development log

pow

tail -f log/development.log

powder

powder applog

缺點:

使用 binding.pry 進行開發有些麻煩,需要安裝 pry-remote

並將原本用的 binding.pry 替換成 binding.remote_pry

然後在執行到中斷點的時候,於 terminal 裡輸入 pry-remote

來取得回應,並進行操作,不過 pry-remote 還是會常常遇到 lag、輸入點錯位、或是莫名斷線等問題,在這邊我的開發模式還是會在用到 binding.pry 時在開一個 rails server 起來就是了(聽起來有點蠢XD)

 
about 2 years ago

啟動 rails server 遇到了這個錯誤嗎?

ActiveRecord::ConnectionNotEstablished

No connection pool with id primary found

這個問題通常是,Rails 的 ActiveRecord 在初始化的時候讀不到你的數據庫(database),可以先檢查 config/database.yml這隻檔案是否存在?

那麼最近很多同學遇到關於 cp config/database.yml.example config/database.yml的問題

覺得這個是屬於安全性的觀念,來寫一下好了

先了解 .gitignore

Git 在項目上傳的時候,通常我們會對整個項目做 tracking(追蹤),所以當追蹤之後只要有任一檔案新增或是變動,Git 都會紀錄,由於我們很常使用 git add . ,所以都會把這次「所有」變動的項目加入 commit。

那麼,如果有很機密的檔案不能上傳,怎麼辦?例如部屬到機器上的資訊,包括 IP, 數據庫帳號密碼,這些東西如果上傳到 Github 的公開專案,豈不是全世界都看光光了,可以任意進出你的機器或數據庫。

因為我們的 Rails 專案底下掌管三種環境(Production, Development, Test)的數據庫資訊都會放在 config/database.yml

所以將我們要過濾掉,不得上傳的檔案路徑,寫進 .gitignore 裡面,他就會過濾這隻檔案,不給予追蹤了

...
...
config/database.yml
...

置放模版

那麼這時候如果你拉下來的專案,沒有了 config/database.yml ,我們又不會特地去背這個,卻又是 Rails Project 運行的必要檔案,怎麼辦?

所以我們會寫一隻「模版」放在專案裡面,但是又要能夠清楚表達他是什麼樣的檔案,又要能被追蹤(因為我們已經先屏蔽了 config/database.yml),所以我們就會做一隻模版放進去

  1. config/database.yml.example
  2. config/database.yml.template

這兩種都可以,或是你有更好的寫法。

那麼經歷以上兩個說明,就可以完整解釋為什麼要在作業 clone 下來運行前輸入這個指令了

cp config/database.yml.example config/database.yml

cp = copy = 複製的意思

cp a.file b.file
解釋:複製 a.file 檔案,並把複製出來的檔案命名為 b.file,且在同一個目錄