├── acid.md ├── index.md ├── transaction.md ├── dil.md ├── assets └── cc-by-nc-sa.png ├── migration.md ├── find.md ├── include--extend.md ├── proc--lambda.md ├── .gitignore ├── nplusone.md ├── beer_type.md ├── hash.md ├── xss.md ├── symbolstring.md ├── concat.md ├── redirect.md ├── aorequalb.md ├── csrf.md ├── SUMMARY.md ├── poly.md ├── resouce--resources.md ├── instanceeval--classeval.md ├── person.md └── README.md /acid.md: -------------------------------------------------------------------------------- 1 | # 資料庫的 ACID 是什麼 -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | # 資料庫的 INDEX 是什麼 -------------------------------------------------------------------------------- /transaction.md: -------------------------------------------------------------------------------- 1 | # Transaction 是什麼 -------------------------------------------------------------------------------- /dil.md: -------------------------------------------------------------------------------- 1 | # 資料庫的 Database Isolation Level 是什麼 -------------------------------------------------------------------------------- /assets/cc-by-nc-sa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unayung/ruby-on-rails-developer-interview-questions/HEAD/assets/cc-by-nc-sa.png -------------------------------------------------------------------------------- /migration.md: -------------------------------------------------------------------------------- 1 | # 為什麼要有 Migration 檔案 2 | 3 | Migration 檔案的用意在於,讓每一次資料庫修改都能夠被記錄進版本控制。以防止多人協作或開發 / 測試 / 正式環境資料庫 schema 的不一致。 4 | 5 | 而另一個較不為人知的優點是,Migration 背後針對不同類型的資料庫 ( 比方 MySQL vs PostgreSQL ) 可以進行相同的處理,減少開發者考慮在 A DB 和 B DB 進行資料庫操作的語法差異。 -------------------------------------------------------------------------------- /find.md: -------------------------------------------------------------------------------- 1 | # Model.find 和 Model.find_by 2 | 3 | 如果我們有一筆記錄例如 4 | ```ruby 5 | Student id = '4' name = 'foobar' 6 | ``` 7 | 如果我們把記錄砍了,那 Student.find(4) 和 Student.find_by(:id => 4) 會發生什麼事? 8 | 9 | ```ruby 10 | Student.find(4).delete 11 | 12 | Student.find(4) 13 | ActiveRecord::RecordNotFound: Couldn't find Student with 'id'=4 14 | # 會產生錯誤 15 | 16 | Student.find_by(:id => 4) 17 | nil 18 | # 只會回傳 nil 19 | ``` -------------------------------------------------------------------------------- /include--extend.md: -------------------------------------------------------------------------------- 1 | # Mixin 中 include 和 Extend 的差別 2 | 3 | ``` 4 | 基本 5 | include module 會讓 module 內定義的 method 成為 instance method 6 | extend module 會讓 module 內定義的 method 成為 class method 7 | 8 | 進階 9 | 當 Klazz.extend(Mod) 時, Klazz 會擁有 Mod 的 method, 視為 class method 10 | 當 obj.extend(Mod) 時, obj 會擁有 Mod 的 method, 視為 instance method, 並只有此 obj 可以呼叫. 11 | 其它同 class 生出來的 object 是不能呼叫的. 12 | ``` 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /proc--lambda.md: -------------------------------------------------------------------------------- 1 | # Proc 和 lambda 的差別 2 | 3 | 簡單來說 Proc 無視傳入的參數是否與 Proc 內定義的參數個數相同,而 lambda 在參數個數不同時會噴錯 4 | 5 | ```ruby 6 | p = Proc.new{|x,y,z| x+y+z} 7 | p.call(1,2,3) 8 | => 6 9 | p.call(1,2,3,4) 10 | => 6 #第四個參數被無視了 11 | 12 | l = lambda{|x,y,z| x+y+z} 13 | l.call(1,2,3) 14 | => 6 15 | l.call(1,2,3,4) 16 | => ArgumentError: wrong number of arguments (given 4, expected 3) #噴錯了 17 | ``` 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /nplusone.md: -------------------------------------------------------------------------------- 1 | # N+1 Query 的處理方向 2 | 3 | Post 有很多 Comments 而有時我們會遇到這種情境 4 | 5 | ```ruby 6 | def users_comments 7 | posts = Post.all 8 | comments = posts.map(&:comments).flatten 9 | @user_comments = comments.select do |comment| 10 | comment.author.username == params[:username] 11 | end 12 | end 13 | ``` 14 | 這邊在取出每一個 post 之後,又對每一個 post 去 query 關連的 comments。就造成所謂的 N+1 Query 效能問題 15 | 16 | 解決方法最直觀就是用 17 | ```ruby 18 | posts = Post.includes(comments: [:author]).all 19 | ``` 20 | 來取代原本的 posts = Post.all 21 | 22 | 可以使用 [bullet](https://github.com/flyerhzm/bullet) 來偵測 N+1 Query -------------------------------------------------------------------------------- /beer_type.md: -------------------------------------------------------------------------------- 1 | # 如何指定 /beer/(beer_type) 這種 route 2 | 3 | 假定我們有以下幾種 beer type 4 | ``` 5 | IPA 6 | brown_ale 7 | pilsner 8 | lager 9 | lambic 10 | hefeweizen 11 | ``` 12 | 如何用同一個 controller action 和設定 routes 來達成 /beer/(beer_type) 顯示不同啤酒的資訊,而不在清單內的則顯示 404 13 | 14 | ```ruby 15 | kinds = %w|IPA brown_ale pilsner lager lambic hefweizen| 16 | resources :beer, only: [:show], constraints: {id: Regexp.new(kinds.join('|'))} 17 | 18 | rails routes 19 | 20 | Prefix Verb URI Pattern Controller#Action 21 | beer GET /beer/:id(.:format) beer#show {:id=>/IPA|brown_ale|pilsner|lager|lambic|hefweizen/} 22 | ``` 23 | -------------------------------------------------------------------------------- /hash.md: -------------------------------------------------------------------------------- 1 | # Hash 和 HashWithIndifferentAccess 的差別 2 | 3 | Hash 在 Ruby 內部實作是用 == 來比對 key. 換句話說在 irb (或純 ruby)的情況下會發生這種情形 4 | ```ruby 5 | irb(main):001:0> h = Hash.new 6 | => {} 7 | irb(main):002:0> h[:v] = '123' 8 | => "123" 9 | irb(main):003:0> h[:v] 10 | => "123" 11 | irb(main):004:0> h['v'] 12 | => nil 13 | ``` 14 | 而在 ActiveSupport 的 HashWithIndifferentAccess 的幫忙之下,我們可以用 :symbol 或 'string' 來取得 Hash 裡的值 15 | ```ruby 16 | irb(main):001:0> hh = HashWithIndifferentAccess.new 17 | => {} 18 | irb(main):002:0> hh[:v] = '456' 19 | => "456" 20 | irb(main):003:0> hh[:v] 21 | => "456" 22 | irb(main):004:0> hh['v'] 23 | => "456" 24 | ``` -------------------------------------------------------------------------------- /xss.md: -------------------------------------------------------------------------------- 1 | # XSS 是什麼 2 | XSS - Cross-Site Scripting 是指在輸入資料的欄位輸入惡意程式碼,使資料外洩或惡作劇跳出視窗,如下 3 | 4 | ```javascript 5 | 6 | 7 | 8 | 9 | 10 | ``` 11 | 12 | 要解決這個問題最基本的方法就是用 escapeHTML() 或 h() 處理並顯示使用者產生的文字 13 | 14 | 但有時候我們必須讓使用者可以輸入 HTML 怎麼辦? 15 | 16 | 那就使用 Rails 提供的 sanitize() 方法以及建立白名單來過濾輸入的 HTML 17 | 18 | 詳細使用參照 [here](http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html#method-i-sanitize) -------------------------------------------------------------------------------- /symbolstring.md: -------------------------------------------------------------------------------- 1 | # Symbol 和 String 的不同 2 | 3 | Symbol 是 immutable 物件而 String 是 mutable 物件。而每次呼叫 Symbol 時可由觀察 object_id 得知,是同一個 object,反觀 string 則是不同一個物件。 4 | 5 | 適當使用 Symbol 可以避免 Server 端的記憶體問題,且在物件的比較上來說,使用 Symbol 比較快速。 6 | ```ruby 7 | irb(main):026:0> :a 8 | => :a 9 | irb(main):027:0> :a.object_id 10 | => 722588 11 | irb(main):028:0> :a.object_id 12 | => 722588 13 | irb(main):029:0> :a.object_id 14 | => 722588 15 | irb(main):030:0> 'a' 16 | => "a" 17 | irb(main):031:0> 'a'.object_id 18 | => 70321956133380 19 | irb(main):032:0> 'a'.object_id 20 | => 70321987377060 21 | irb(main):033:0> 'a'.object_id 22 | => 70321987372240 23 | irb(main):041:0> 'a'.equal?('a') 24 | => false 25 | irb(main):042:0> :a.equal?(:a) 26 | => true 27 | ``` -------------------------------------------------------------------------------- /concat.md: -------------------------------------------------------------------------------- 1 | # 請解釋對字串使用 += 和使用 concat 方法有何差異 2 | 3 | 對字串使用 += 方法,例如 a += b。事實上是再產生了一個 a 物件並把 a+b 的結果丟進新的 a 物件。我們可以觀察 object_id 來得知這樣的行為。 4 | 5 | ```ruby 6 | irb(main):041:0> x = "hello" 7 | => "hello" 8 | irb(main):042:0> x.object_id 9 | => 70232477009280 10 | irb(main):043:0> x += " world" 11 | => "hello world" 12 | irb(main):044:0> x 13 | => "hello world" 14 | irb(main):045:0> x.object_id 15 | => 70232475548960 16 | ``` 17 | 18 | 而 concat 則是對同一個物件進行操作 19 | 20 | ```ruby 21 | irb(main):049:0> x = "hello" 22 | => "hello" 23 | irb(main):050:0> x.object_id 24 | => 70232488144300 25 | irb(main):051:0> x.concat " world" 26 | => "hello world" 27 | irb(main):052:0> x 28 | => "hello world" 29 | irb(main):053:0> x.object_id 30 | => 70232488144300 31 | ``` -------------------------------------------------------------------------------- /redirect.md: -------------------------------------------------------------------------------- 1 | # redirect_to 和 render 有什麼不同 2 | 3 | redirect_to 可以視為跳轉到別頁。包括跳轉到別的網站也是用 redirect_to 。因此使用 redirect_to 會造成 URL 的改變。 4 | 5 | render 則是用於告訴 Rails "我要顯示什麼樣的畫面 / 資料在 browser 上" 而事實上 Rails 本身在每一個 controller action 都自動進行尋找並 render 對應的 template。所以 render 不會造成 URL 的改變。 6 | 7 | 額外一提的是 render 會把之前在 form 裡填寫的內容一併顯示。對於註冊流程或是使用者體驗上是相當方便的。 8 | 9 | 以實際例子來看 10 | 11 | ```ruby 12 | def create 13 | @user=User.new(params[:user]) 14 | if @user.save 15 | redirect_to :index 16 | else 17 | render :new #you should render to fill fields after error message 18 | end 19 | end 20 | 21 | 如果 @user.save 成功了,就跳轉到 index action。 22 | 如果 @user.save 失敗了,就 render "new" 這個 action 的 template 23 | ( 也就是 create 的上一步,此時可注意 URL 還是會在 create 的 path ) 24 | ``` -------------------------------------------------------------------------------- /aorequalb.md: -------------------------------------------------------------------------------- 1 | # 請解釋這個語法 a ||= b 2 | 3 | 當 a 有值 ( 非 nil 非 false ) 時, a 保持原值 4 | 5 | 當 a 為 nil / false 時, a = b 6 | 7 | 我們看以下的範例 8 | 9 | ```ruby 10 | irb(main):024:0> a = nil 11 | => nil 12 | irb(main):025:0> b = 10 13 | => 10 14 | irb(main):026:0> a ||= b 15 | => 10 16 | irb(main):027:0> a 17 | => 10 18 | 19 | irb(main):028:0> a = false 20 | => false 21 | irb(main):029:0> b = 20 22 | => 20 23 | irb(main):030:0> a ||= b 24 | => 20 25 | irb(main):031:0> a 26 | => 20 27 | 28 | irb(main):032:0> a = "" 29 | => "" 30 | irb(main):033:0> b = "abc" 31 | => "abc" 32 | irb(main):034:0> a ||= b 33 | => "" 34 | irb(main):035:0> a 35 | => "" 36 | 37 | irb(main):037:0> a = 689 38 | => 689 39 | irb(main):038:0> b = 633 40 | => 633 41 | irb(main):039:0> a ||= b 42 | => 689 43 | irb(main):040:0> a 44 | => 689 45 | ``` -------------------------------------------------------------------------------- /csrf.md: -------------------------------------------------------------------------------- 1 | # CSRF 是什麼 2 | 3 | CSRF - Cross-Site Request Forgery 是指攻擊者惡意在可插入程式片段的地方放入如 4 | 5 | ```html 6 | 7 | ``` 8 | 9 | 的程式碼,等到擁有管理權限的人看到這張假圖時,送出這個 request 給 server 然後刪除所有 post 10 | 11 | 如何防範 CSRF 攻擊呢? 首先從 routes 的角度來設計。 12 | 13 | > 所有讀取、查詢性質操作,都應該用 _GET_,而會修改或刪除到資料的,則要用 _POST_ 、 _PATCH/PUT_ 或 _DELETE_ 。這樣的設計,就可以防止上面的惡意程式碼了,因為在瀏覽器中必須用表單 _form_ 才能送出 _POST_ 請求。 from [Ruby on Rails實戰聖經](https://ihower.tw/rails/security.html#sec1) 14 | 15 | 而從 Rails 架構本身的防範來說,我們可以使用 protect_from_forgery 這個 method 來阻擋攻擊 16 | 17 | ```ruby 18 | class ApplicationController < ActionController::Base 19 | protect_from_forgery with: :exception 20 | end 21 | ``` 22 | 這個 method 會在所有表單自動插入一組 token 而在每次送 _POST_ 的時候去和 session 裡的 token 比對是否正確,如果不正確就阻止 _POST_ 動作的發生。而 Layout中也有一段 <%= csrf_meta_tags %> 是給 JavaScript 讀取 token 用的。 23 | 24 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [Symbol 和 String](symbolstring.md) 5 | * [proc 和 lambda](proc--lambda.md) 6 | * [include 和 extend](include--extend.md) 7 | * [instance\_eval 和 class\_eval](instanceeval--classeval.md) 8 | * [resouce 和 resources](resouce--resources.md) 9 | * [Hash 和 HashWithIndifferentAccess](hash.md) 10 | * [Model.find 和 Model.find_by](find.md) 11 | * [redirect_to 和 render](redirect.md) 12 | * [什麼是 Polymorphic Association](poly.md) 13 | * [N+1 Query](nplusone.md) 14 | * [為什麼要有 Migration 檔案](migration.md) 15 | * [Transaction 是什麼](transaction.md) 16 | * [如何用單一 action 套用 /beer/(beer\_type) 這種 route](beer_type.md) 17 | * [如何讓 Person model 可以指定另一個 person 為 parent](person.md) 18 | * [請解釋這個語法 a ||= b](aorequalb.md) 19 | * [請解釋對字串使用 += 和使用 concat 方法有何差異](concat.md) 20 | * [CSRF 是什麼](csrf.md) 21 | * [XSS 是什麼](xss.md) 22 | * [資料庫的 INDEX 是什麼](index.md) 23 | * [資料庫的 ACID 是什麼](acid.md) 24 | * [資料庫的 Database Isolation Level 是什麼](dil.md) 25 | * [資料庫的 Database Isolation Level 是什麼](dil.md) -------------------------------------------------------------------------------- /poly.md: -------------------------------------------------------------------------------- 1 | # 什麼是 Polymorphic Association 多型關聯 2 | 3 | 使用場景例如,你的網站上有圖片 (Image) 和影片 (Video) 兩種 model,而 PM 告訴你,他想要讓這兩種 model 都可以留言 (Comment) 4 | 5 | 如果不使用 Polymorphic 的話,那你可能會產生 ImageComment 和 VideoComment 兩種 model 。而這兩者的行為又完全相同,這就違反了 DRY 的原則。 6 | 7 | 我們可以使用 Polymorphic Association 來解決這樣的需求 8 | 9 | ```ruby 10 | rails g model comment content:text commentable_id:integer commentable_type 11 | 12 | 會產生這樣的 migration 檔案 13 | 14 | class CreateComments < ActiveRecord::Migration 15 | def change 16 | create_table :comments do |t| 17 | t.text :content 18 | t.integer :commentable_id 19 | t.string :commentable_type 20 | 21 | t.timestamps 22 | end 23 | end 24 | end 25 | 26 | 或是可以寫成這樣 27 | 28 | class CreateComments < ActiveRecord::Migration 29 | def change 30 | create_table :comments do |t| 31 | t.text :content 32 | t.belongs_to :commentable, :polymorphic => true 33 | 34 | t.timestamps 35 | end 36 | end 37 | end 38 | 39 | 中間 t.belongs_to :commentable, :polymorphic => true 40 | 則會自動產生 commentable_id 和 commentable_type 這兩個欄位 41 | ``` 42 | 43 | 而在 Model 的部份,只要這樣設定即可 44 | 45 | ```ruby 46 | class Comment < ActiveRecord::Base 47 | belongs_to :commentable, :polymorphic => true 48 | end 49 | 50 | class Video < ActiveRecord::Base 51 | has_many :comments, :as => :commentable 52 | end 53 | 54 | class Image < ActiveRecord::Base 55 | has_many :comments, :as => :commentable 56 | end 57 | ``` 58 | 59 | 這樣一來就算之後還有第三、四、N 種 Model 可以被 Comment。也只要加入上述的 relation 就可以搞定了。 -------------------------------------------------------------------------------- /resouce--resources.md: -------------------------------------------------------------------------------- 1 | # resource 和 resources 的差別 2 | 3 | 從字面上來看 resouce 是單數而 resources 是複數,也就是說如果你想要列出某種類 model 的列表. 你應該選用 resources 來符合 rails 的 convention. 而兩者預設產生出來的 routes 差別在於有沒有 index action 和對應的 path / url 4 | 5 | ```ruby 6 | # 假設每個使用者只有一組 profile 可以設定 7 | 8 | resource :profile # in routes.rb 9 | 10 | rails routes 11 | 12 | new_profile GET /profile/new(.:format) profiles#new 13 | edit_profile GET /profile/edit(.:format) profiles#edit 14 | profile GET /profile(.:format) profiles#show 15 | PATCH /profile(.:format) profiles#update 16 | PUT /profile(.:format) profiles#update 17 | DELETE /profile(.:format) profiles#destroy 18 | POST /profile(.:format) profiles#create 19 | 20 | # 可以發現並沒有建立 index action 的 route 21 | ``` 22 | ```ruby 23 | # 假設每個使用者可以設定多組 profile 24 | 25 | resources :profiles # in routes.rb 26 | 27 | rails routes 28 | 29 | profiles GET /profiles(.:format) profiles#index 30 | new_profile GET /profiles/new(.:format) profiles#new 31 | edit_profile GET /profiles/:id/edit(.:format) profiles#edit 32 | profile GET /profiles/:id(.:format) profiles#show 33 | PATCH /profiles/:id(.:format) profiles#update 34 | PUT /profiles/:id(.:format) profiles#update 35 | DELETE /profiles/:id(.:format) profiles#destroy 36 | POST /profiles(.:format) profiles#create 37 | 38 | # 這個情況下就有 profiles 列表的存在,且針對某一 profile 的操作需要 pass id 以找到特定記錄 39 | ``` -------------------------------------------------------------------------------- /instanceeval--classeval.md: -------------------------------------------------------------------------------- 1 | # instance\_eval 和 class\_eval 的差別 2 | 3 | ``` 4 | 先講結論 5 | instance_eval 可以定義 instance method 但不能被同 class 的其它 instance 呼叫, 6 | 也可以定義 class method 因為 class 也是 Class 的一個 instance 7 | 8 | class_eval 可以定義 instance method 並且可以被同 class 的其它物件呼叫 9 | 是不是聽起來有點玄妙? 10 | 我們來看底下的例子 11 | ``` 12 | 13 | ```ruby 14 | class MyClass 15 | def initialize(num) 16 | @num = num 17 | end 18 | end 19 | 20 | a = MyClass.new(1) 21 | b = MyClass.new(2) 22 | ``` 23 | 24 | 當我們想要檢視 a,b 物件內的 num 值時,我們會用 a.num 來試試看 25 | 26 | ```ruby 27 | a.num 28 | => NoMethodError: undefined method `num' for # 29 | ``` 30 | 31 | 噴錯了,因為我們沒有 def num 這個 method 32 | 那我們用 instance\_eval 來試試看吧 33 | 34 | ```ruby 35 | a.instance_eval do 36 | def num 37 | puts @num 38 | end 39 | end 40 | 41 | a.num 42 | => 1 43 | b.num 44 | => NoMethodError: undefined method `num' for # 45 | ``` 46 | 47 | 又噴錯了,因為我們只有針對 a 這個物件去寫 instance\_eval, 但 b 是看不到 num 這個 method 48 | 49 | 那如果我們針對 MyClass 用 instance\_eval 會發生什麼事呢? 50 | 51 | ```ruby 52 | MyClass.instance_eval do 53 | def num 54 | @num 55 | end 56 | end 57 | 58 | b.num 59 | => NoMethodError: undefined method `num' for # 60 | ``` 61 | 62 | 又噴錯了,因為我們是對 MyClass 這個 Class 的 instance 去寫 instance\_eval 63 | 上面的 code 執行起來是這樣 64 | 65 | ```ruby 66 | MyClass.num 67 | => nil # 因為我們沒有給值丟進 num 裡就直接 call num 這個變數. 自然是 nil 68 | ``` 69 | 70 | 那麼正確讓 a.num / b.num 都可以回傳正確值的作法是什麼呢? 71 | 72 | ```ruby 73 | MyClass.class_eval do 74 | def num 75 | @num 76 | end 77 | end 78 | 79 | a.num 80 | => 1 81 | b.num 82 | => 2 83 | ``` 84 | 85 | 事實上我們可以把上面 class\_eval 的例子視為平常在寫 instance method 的寫法,如下面所示 86 | 87 | ```ruby 88 | class MyClass 89 | def num 90 | @num 91 | end 92 | end 93 | ``` 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /person.md: -------------------------------------------------------------------------------- 1 | # 如何讓 Person model 可以指定另一個 person 為 parent 2 | 3 | ```ruby 4 | irb(main):001:0> john = Person.create(name: "John") 5 | irb(main):002:0> jim = Person.create(name: "Jim", parent: john) 6 | irb(main):003:0> bob = Person.create(name: "Bob", parent: john) 7 | irb(main):004:0> john.children.map(&:name) 8 | => ["Jim", "Bob"] 9 | ``` 10 | 如何達成這樣的關連呢?首先我們要知道 association 的 target class 是可以另外指定的,而外鍵的欄位也是可以自己定義 11 | 12 | ```ruby 13 | rails g migration add_parent_id_to_person 14 | # 先增加一個整數欄位 parent_id 到 person table 15 | 16 | class Person < ActiveRecord::Base 17 | belongs_to :parent, class: Person 18 | has_many :children, class: Person, foreign_key: :parent_id 19 | end 20 | ``` 21 | 22 | 這個問題還可以延伸下去,如果我想達成這樣的效果,需要怎麼實作呢? 23 | ```ruby 24 | irb(main):001:0> sally = Person.create(name: "Sally") 25 | irb(main):002:0> sue = Person.create(name: "Sue", parent: sally) 26 | irb(main):003:0> kate = Person.create(name: "Kate", parent: sally) 27 | irb(main):004:0> lisa = Person.create(name: "Lisa", parent: sue) 28 | irb(main):005:0> robin = Person.create(name: "Robin", parent: kate) 29 | irb(main):006:0> donna = Person.create(name: "Donna", parent: kate) 30 | irb(main):007:0> sally.grandchildren.map(&:name) 31 | => ["Lisa", "Robin", "Donna"] 32 | ``` 33 | 34 | 這邊考的是 has_many ... :through => 這個概念 35 | 36 | ```ruby 37 | class Person < ActiveRecord::Base 38 | belongs_to :parent, class: Person 39 | has_many :children, class: Person, foreign_key: :parent_id 40 | has_many :grandchildren, class: Person, through: :children, source: :children 41 | end 42 | ``` 43 | 44 | 這個範例解釋得很好 45 | ```ruby 46 | Say you have these models: 47 | 48 | Car 49 | Engine 50 | Piston 51 | 52 | A car has_one :engine 53 | An engine belongs_to :car 54 | An engine has_many :pistons 55 | Piston belongs_to :engine 56 | 57 | A car has_many :pistons, through: :engine 58 | Piston has_one :car, through: :engine 59 | 60 | Essentially you are delegating a model relationship to another 61 | model, so instead of having to call car.engine.pistons, you can 62 | just do car.pistons 63 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 常見的 Ruby on Rails 工程師面試問題 2 | 3 | 收錄一些業界常見/常問的面試問題和翻譯解答 4 | 5 | 解答不見得完整和精確,但在面試的環境下回答應該是足夠的 6 | 7 | 有需要改正或有什麼要新增 / 補充的地方也請大家發 PR 8 | 9 | [開始閱讀](https://unayung.gitbooks.io/ruby-on-rails-developer-interview-questions/content/) 10 | 11 | source 在 [Github](https://github.com/Unayung/ruby-on-rails-developer-interview-questions) 12 | 13 | --- 14 | 15 | 目錄 16 | 17 | * [Introduction](README.md) 18 | * [Symbol 和 String](symbolstring.md) 19 | * [proc 和 lambda](proc--lambda.md) 20 | * [include 和 extend](include--extend.md) 21 | * [instance\_eval 和 class\_eval](instanceeval--classeval.md) 22 | * [resouce 和 resources](resouce--resources.md) 23 | * [Hash 和 HashWithIndifferentAccess](hash.md) 24 | * [Model.find 和 Model.find_by](find.md) 25 | * [redirect_to 和 render](redirect.md) 26 | * [什麼是 Polymorphic Association](poly.md) 27 | * [N+1 Query](nplusone.md) 28 | * [為什麼要有 Migration 檔案](migration.md) 29 | * [Transaction 是什麼](transaction.md) 30 | * [如何用單一 action 套用 /beer/(beer\_type) 這種 route](beer_type.md) 31 | * [如何讓 Person model 可以指定另一個 person 為 parent](person.md) 32 | * [請解釋這個語法 a ||= b](aorequalb.md) 33 | * [請解釋對字串使用 += 和使用 concat 方法有何差異](concat.md) 34 | * [CSRF 是什麼](csrf.md) 35 | * [XSS 是什麼](xss.md) 36 | * [資料庫的 INDEX 是什麼](index.md) 37 | * [資料庫的 ACID 是什麼](acid.md) 38 | * [資料庫的 Database Isolation Level 是什麼](dil.md) 39 | 40 | 參考資料 41 | 42 | * [Ruby on Rails 實戰聖經](https://ihower.tw/rails/) 43 | * [8 Essential Ruby on Rails Interview Questions](https://www.toptal.com/ruby-on-rails/interview-questions) 44 | * [11 Ruby on Rails Interview Practice Questions](https://www.codementor.io/ruby-on-rails/tutorial/ruby-on-rails-interview-questions) 45 | * [15 Questions to Ask During a Ruby Interview](https://gist.github.com/ryansobol/5252653) 46 | 47 | 版權許可 48 | 49 | 採用創用CC授權4.0 "姓名標示─非商業性─相同方式分享(BY-NC-SA)" 授權。 50 | 51 | ![](/assets/cc-by-nc-sa.png) 52 | 53 | 本授權條款允許使用者重製、散布、傳輸以及修改著作,但不得為商業目的之使用。若使用者修改該著作時,僅得依本授權條款或與本授權條款類似者來散布該衍生作品。使用時必須按照著作人指定的方式表彰其姓名。 54 | 55 | 詳細資訊請參考 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/)。 56 | 57 | --------------------------------------------------------------------------------