Hotwireã®è¯ãã£ãç¹ãè¾ãã£ãç¹ãåãã¦ããã±ã¼ã¹ãåãã¦ããªãã±ã¼ã¹
ï¼èªåã¯Railsãæ¸ããã¨ãå¤ããããã³ãã¨ã³ãã®çµé¨ã¯ä¹ããã§ããè¦æ¹ã«ã ãã¶åããããã¨æãã¾ãã®ã§ããã®ãããå·®ãå¼ãã¦ãèªã¿ããã ããã°ã¨æãã¾ããðââï¸ï¼
ããã«ã¡ã¯ããHotwireãä»äºã§ä½¿ãæ©ä¼ããã£ãã®ã§ãå®éã«ä½¿ã£ã¦ã¿ã¦æãããè¯ãã£ãç¹ãè¾ãã£ãç¹ãåãã¦ããã±ã¼ã¹ãåãã¦ããªãã±ã¼ã¹ãå ±æãã¾ããã
- Hotwireã¨ã¯ï¼
- è¯ãã£ãç¹
- è¾ãã£ãç¹ã»è¾ããªããããªç¹
- DOMæ´æ°æã«ã¬ã¹ãã³ã¹ãå¾ ããªãã¨ãããªã
- SPAã®ã¦ã¼ã¶ã¼ä½é¨ã¨ã¯ã ãã¶éã
- Herokuã使ãã¥ãã
- TypeScriptã使ãã¥ãã
- Stimulusãé£ãã
- æ¥æ¬èªã®æ å ±ãå°ãªã
- é»éè¡æ
- å¯è±ªç
- partialã ããã«ãªã
- ãµã¼ãã¼ã®ãªã½ã¼ã¹ãé£ã
- åæ¥ã¯é£ãã
- å¾ããSPAã«ããã®ã¯è¾ãã
- åãã¦ããã±ã¼ã¹
- åãã¦ããªãã±ã¼ã¹
- Hotwireã¨åè¨ä¼ç¤¾
- ã¾ã¨ã
- åè
Hotwireã¨ã¯ï¼
ã¾ãã¯Hotwireã®ç°¡åãªèª¬æãå°ãã ãï¼ãã¡ãã®æ¬ã®ã¾ã¨ãã§ãï¼ã
Hotwireã¯Rails7ããRailsã®ããã³ãã¨ã³ãã®ããã©ã«ãã¨ãªã£ãæè¡ã§ããTurboã¨Stimulusã¨ãã2ã¤ã®JSã®ãã¬ã¼ã ã¯ã¼ã¯ããæ§æããã¾ããHotwireã¯ãã®2ã¤ã©ã¤ãã©ãªã®ç·ç§°ã§ããTurboã¯Turbo DriveãTurbo FramesãTurbo Streamsã¨ãã3ã¤ã®æè¡ããæ§æããããããHotwireã®ç»å ´äººç©ã¯ä»¥ä¸ã®ããã«ãªãã¾ãã
- Turbo
- Turbo Drive
- Turbo Frames
- Turbo Streams
- Stimulus
ï¼å®éã«ã¯ã¢ãã¤ã«ã¢ããªéçºã®ããã®Turbo Nativeã¨Stradaã¨ããæè¡ãããã®ã§ããããã®è¨äºã§ã¯Webéçºã®ããã®æè¡ã«çµãã¾ããï¼
Turbo Driveã¨ã¯ï¼
Turbo Driveã¯ç»é¢é·ç§»ãé«éã«ãã¦ãããæè¡ã§ãã
Turbo Driveã¯Turbolinksã®ååãå¤ãããã®ã§ãåºæ¬çãªæ©è½ã¯Turbolinksã¨åãã§ãããªã³ã¯ããã©ã¼ã ã®ãªã¯ã¨ã¹ããTurbo Driveãã¤ã³ã¿ã¼ã»ãããã¦ãfetchã«ããéåæãªã¯ã¨ã¹ãã«ãã¦ããã¾ããããã¦ã¬ã¹ãã³ã¹ãããHTMLã®<body>
è¦ç´ ã ããæãåºãã¦ãç¾å¨ã®ãã¼ã¸ã®<body>
è¦ç´ ãå·®ãæ¿ãã¦ããã¾ãã
é常ã®ç»é¢é·ç§»ãHTMLã丸ãã¨å¤ããã«å¯¾ãã¦ãTurbo Driveã§ã®ç»é¢é·ç§»ã¯<body>
ã ããç½®æãã¦ããã¾ãï¼æ£ç¢ºã«ã¯<body>
ã®ç½®æã«å ãã¦ã<head>
ã®ä¸é¨ããã¼ã¸ããã¾ãï¼ãããã®ä½ãå¬ãããã¨è¨ãã¨ãç»é¢é·ç§»ãã¦ãä»ã®ãã¼ã¸ã®CSSã»JSããã®ã¾ã¾å©ç¨ã§ãããããCSSã»JSãåæåãã¦ãã¼ã¸ã«é©ç¨ããå¦çãã¹ãããã§ãã¾ããããã«ãã£ã¦ç»é¢é·ç§»ãé«éã«ãªãã¾ãã
Turbo Framesã¨ã¯ï¼
Turbo Framesã¯Turbo Driveã®é¨åç½®æçã§ãã
Turbo Driveã<body>
è¦ç´ å
¨ä½ãå·®ãæ¿ããã®ã«å¯¾ãã¦ãTurbo Framesã¯<turbo-frame>...</turbo-frame>
ã¨ããã«ã¹ã¿ã è¦ç´ ã§å²ã£ãç®æã ããå·®ãæ¿ãã¾ããç»é¢ã®ä¸é¨ã ãããæ´æ°ããªããããªå ´åã«ã¯ãTurbo Driveã®ä»£ããã«Turbo Framesã使ããã¨ã§é«éåã§ãã¾ãã
ä¸ã®GIFã§è©³ç´°ï¼_cat.html.erb
ï¼ã«ç¸å½ããç®æãç·¨éï¼edit.html.erb
ï¼ã«å·®ãæ¿ãã¦ãã¾ãã
Turbo Streamsã¨ã¯ï¼
Turbo Streamsã¯è¤æ°ç®æã®DOMãåæã«æ´æ°ã§ãã¾ãã
Turbo Framesã§æ´æ°ã§ããã®ã¯<turbo-frame>
ã§å²ã£ã1ç®æã ãã¨ããå¶ç´ãããã¾ãããã®ããè¤æ°ç®æãåæã«æ´æ°ãããå ´åã«ã¯Turbo Streamsã使ãã¾ãã
ä¸ã®GIFã§ã¯ç·¨éï¼edit.html.erb
ï¼é¨åã詳細ï¼_cat.html.erb
ï¼ã«å·®ãæ¿ãã¦ãããã«Flashï¼_flash.html.erb
ï¼ãæ°ãããã®ã«å·®ãæ¿ãã¦ãã¾ãã
ãã¨Turbo FramesãDOMã®ç½®æããã§ããªãã®ã«å¯¾ãã¦ãTurbo Streamsã§ã¯DOMã®è¿½å ã»æ´æ°ã»åé¤ããããã¨ãå¯è½ã§ãã
ä»ã«ãActionCableï¼WebSocketï¼ã¨çµã¿åããã¦ä½¿ããã¨ã§ããã£ããã®ãããªãªã¢ã«ã¿ã¤ã ãªã¢ããªã±ã¼ã·ã§ã³ãä½ããããã¾ãã
Stimulusã¨ã¯ï¼
Stimulusã¯Hotwireã§JSãæ¸ãéã®ã¬ã¼ã«ã®ãããªãã®ã§ããçDOMæä½ã®æ¹æ³ãæä¾ãã¦ããã¾ãã
Turboã使ãã¨JSãæ¸ããã«ãµã¼ãã¼ãµã¤ãã¬ã³ããªã³ã° + fetchã§DOMãæ´æ°ã§ããããã«ãªãã¾ãããã®çµæãReactãVueã使ãã®ã«æ¯ã¹ã¦ãJSãæ¸ãéã¯åçã«æ¸ãã¾ããããã§ãJSãå¿ è¦ãªã±ã¼ã¹ã¯åºã¦ãã¾ãããããªæã«ã¯ãStimulusãç¨æããã¬ã¼ã«ã®ä¸ã«JSãæ¸ããã¨ã«ãªãã¾ãã
MutationObserverã§DOMã®å¤æ´ãç£è¦ãã¦ãæ¯ãèããä¸ããã¹ãHTMLãæ¤åºãããã¨èªåã§ã¢ã¿ããããã¾ãããã®ããDOMãå·®ãæ¿ããTurboã¨ç¸æ§ãè¯ããã¬ã¼ã ã¯ã¼ã¯ã¨ãªã£ã¦ãã¾ãã
Hotwireã®ãã¢
ãã¢1ã¯ç´ ã®Railsã§ä½ã£ã管çç»é¢ã§ãï¼ãã®è¨äºã§ã¯ãHotwireãReactçã®ã¢ãã³ãªããã³ãã¨ã³ãã®æè¡ã使ããªããæãªããã®Railsã®ãã¨ããç´ ã®Railsãã¨å¼ã¶ããã«ãã¾ãï¼ã
ãã¢1ã¯ãã¡ããã触ãã¾ã
ãã¢2ã¯Hotwireã使ãSPA風ã«ãã管çç»é¢ã§ãã
ãã¢2ã¯ãã¡ããã触ãã¾ã
ãã¢2ã§ã¯ãã¢1ã®æ©è½ï¼ãã¼ã¸ãã¼ã·ã§ã³ã»ã½ã¼ãã»æ¤ç´¢ã»ç·¨éã»ç»é²ã»åé¤ï¼ãHotwireã使ãç»é¢é·ç§»ããã«è¡ããããã«ãã¦ãã¾ãããã¢1ã®ã³ã¼ããï¼è¦ãç®ã®å¤æ´ãé¤ãã¨ï¼æ°è¡ä¿®æ£ããã ãã§ãSPA風ã«ã§ãã¾ãããJavaScriptã¯1è¡ãæ¸ãã¦ãã¾ããã
è¯ãã£ãç¹
Hotwireã使ã£ã¦ã¿ã¦è¯ãã£ãã¨æããç¹ã¯ä»¥ä¸ã®ã¨ããã§ããæãã¤ãã¾ã¾ã«æ¸ããã®ã§ããã¾ãæ´çããã¦ãã¾ããããã容赦ãã ãããðââï¸
ãµã¼ãã¼ãµã¤ãã«éä¸ã§ãã
Hotwireã®ç¹å¾´ã¯ãµã¼ãã¼ãHTMLãã¬ã¹ãã³ã¹ããã¨ããã«ããã¾ãã
Hotwireã使ãã¨ããã©ã¼ã ã»ãªã³ã¯ããã®ãªã¯ã¨ã¹ãã¯å ¨ã¦fetchã«ããéåæãªã¯ã¨ã¹ãã«ãªãã¾ãããã®fetchã«å¯¾ãã¦ããµã¼ãã¼ã¯HTMLãã¬ã¹ãã³ã¹ãã¾ãã
Reactï¼ãVueçã®JSã©ã¤ãã©ãªï¼ãå©ç¨ãã¦SPAãä½ãå ´åã«ã¯ãfetchã«å¯¾ãã¦ãµã¼ãã¼ã¯JSONãã¬ã¹ãã³ã¹ãã¦ãã¯ã©ã¤ã¢ã³ãå´ã§DOMãæ§ç¯ãããã¨ãå¤ãã¨æãã¾ãããã®ããæ¹ã ã¨ããã¯ã¨ã³ãã¨ããã³ãã¨ã³ãã§2ã¤ã®ã¢ããªã±ã¼ã·ã§ã³ãä½ããã¨ã«ãªã£ã¦ãã¾ãã¾ããåããããªãã¸ãã¯ãããã¯ã¨ã³ãã¨ããã³ãã¨ã³ãã®ä¸¡æ¹ã«æ¸ãå¿ è¦ãåºã¦ãã¾ãã
Hotwireã§ã¯fetchã«å¯¾ãã¦JSONã§ã¯ãªãHTMLãã¬ã¹ãã³ã¹ãã¾ããããã«ãã£ã¦ã¬ã³ããªã³ã°ã¯ãµã¼ãã¼ãµã¤ãã§ã®ã¿è¡ãããã«ã§ãã¾ããç¶æ 管çããã®ã¯ãµã¼ãã¼ãµã¤ãã ãã§ããããã¢ãã«ãããªãã¼ã·ã§ã³ã¯ãµã¼ãã¼ãµã¤ãã«ã ãç¨æããã°ãããªãã¾ããããã°ã©ãã¯ãµã¼ãã¼ãµã¤ãã«éä¸ã§ããããã«ãªããJSã¯ãµãã¼ãçã«å°ãã ã使ããã®ï¼ãããã¯ã»ã¨ãã©ä½¿ããªããã®ï¼ãã¨ããç«ã¡ä½ç½®ã«ãªãã¾ãã
ãã¼ã ããµã¼ãã¼ãµã¤ãã¨ã³ã¸ãã¢ã ãã§æ§æã§ããããã«ãªãã¾ãã
Railsã®è³ç£ããã«ã«æ´»ããã
ã¬ã³ããªã³ã°ãå ¨ã¦ãµã¼ãã¼ãµã¤ãã§è¡ãã¨ããããæ¹ã¯ãæãªããã®Railsã®ããæ¹ã¨åãã§ããèªåã®ä¸ã«ãä¼ç¤¾ã®ä¸ã«ãRailsã ã£ããããæ¸ãã°ãããã¨ããRailsã®è³ç£ã沢山æºã¾ã£ã¦ãã¾ããHotwireã使ã£ãéçºã ã¨ããã®è³ç£ããã«ã«æ´»ãããã¨ãã§ãã¾ãã
ãã¼ã¿ã¢ããªã³ã°ã¨URLè¨è¨ããé©åã«ãã¦ããã°ãã³ã³ããã¼ã©ã¼ããã¥ã¼ã¯ã»ã¼æ©æ¢°çã«æ§ç¯ã§ãããã¨ããã®ãRailsã®é åã®1ã¤ã ã¨æãã¦ãã¾ããããã¼ãã«ã¨ã¢ãã«ãç´æ¥ç´ä»ããªãå ´åã§ããApplicationModelã使ããªã©ãã¦ã¢ãã«ãããã£ããä½ã£ã¦ããã°ãã³ã³ããã¼ã©ã¼ããã¥ã¼ã¯scaffoldã¨åãããã«ä½ãã°ããã¨ããå®å¿æãããã¾ãããªã®ã§Hotwireã§ãããåãæ»ããæããã£ã¦ãããããããã¨ãªãã¾ããããããkaminariãransackã®ãããªã¢ãã«ãããã¥ã¼ãæ§ç¯ããããã®ã馴æã¿ã®gemã使ãã¦ãããããTurboã§ç°¡åã«SPA風ã«ã§ããã®ã§ããããããããããã¨ãªãã¾ããã
ï¼Hotwireã¯Railsã«ä¾åããªãæè¡ãªã®ã§ãRailsã®é¨åã¯ã好ããªãµã¼ãã¼ãµã¤ãã®ãã¬ã¼ã ã¯ã¼ã¯ã«ç½®ãæããããã¨æãã¾ãããã èªåã¯Railsã§ããHotwireã使ã£ããã¨ããªãã®ã§ããã®è¨äºã§ã¯Railsã«éå®ãã¦è©±ããã¾ããï¼
å¾ä»ãã§æ®µéçã«SPA風ã®æåã追å ã§ãã
Hotwireã®ç´ æ´ãããç¹ã®1ã¤ã¨ãã¦ãæ¢åã®Railsã¢ããªã«å¯¾ãã¦å¾ä»ãã§æ®µéçã«SPA風ã®æåã追å ã§ããç¹ãããã¾ããæ¢åã®Railsã¢ããªã®ã³ã¼ããå°ãä¿®æ£ããã ãã§ãSPAã®ã¡ãªããã享åã§ããããã«ãªãã¾ããåãããHotwireã使ã£ã¦éçºãããã¨ãå¯è½ã§ãããæåã¯æ £ã親ããã ç´ ã®Railsã§éçºãã¦ãéè¦ãªæ©è½ã ããHotwireã使ãä½ãè¾¼ãã§ãããã¨ãç°¡åã«ã§ãã¾ãããã¢ã§ã¯ãã¾ãã¯ç´ ã®Railsã§éçºãã¦ããï¼ãã¢1ï¼ãå¾ä»ãã§Hotwireã使ã£ã¦SPA風ã®æåã追å ãã¦ãã¾ãï¼ãã¢2ï¼ã
å°ãã®å´åã§SPAã®ã¡ãªããã享åã§ããããã¨ãã£ã¦ãå ¨ã¦ã®ãã¼ã¸ãHotwireã§ä½ãè¾¼ãå¿ è¦ã¯ããã¾ãããå ¨ã¦ã®ãã¼ã¸ãåãã ãã®éè¦åº¦ã§ã¯ããã¾ãããä¾ãã°è«æ±ãè¦ãããã®ãã¼ã¸ã§ããã°ãæã«1度ãã使ãããªãããããã¾ããããããªæ©è½ãä½ãè¾¼ãå¿ è¦ã¯ããã¾ãããHotwireã使ãã°ãéè¦ã§ãªãæ©è½ã¯ä»ã¾ã§ã®Railsã¨åãããã«ä½ããéè¦ãªæ©è½ã ããä½ãè¾¼ãã§ãããã¨ãããã¨ãç°¡åã«ã§ãã¾ãã
Turbo FramesãTurbo Streamsã®å©ç¨ã¯ãå°ãã ãã¨ã¯ãããã¢ããªã±ã¼ã·ã§ã³ã«è¤éããããããã¾ãããªã®ã§ã¾ãã¯Turbo Driveã使ããããã«å¿ è¦ã§ããã°Turbo Framesã»Turbo Streamsã使ããããã«å¿ è¦ã§ããã°Stimulusã使ãã®ãããã¨æãã¾ãã
ã¾ãã¯ç´ ã®Railsã§ä½ã£ã¦ããã¦ãéè¦ãªé¨åã ãã段éçã«ä½ãè¾¼ãã§ããããã¨ãHotwireã®å¼·ã¿ã§ãã
åè
å¦ç¿ã³ã¹ããä½ã
Hotwireã¯å¦ç¿ã³ã¹ããä½ãã§ããTurboãStimulusãå ¬å¼ããã¥ã¡ã³ããèªãã ããªãæ°æéã§èªãã¾ããå¨è¾ºæè¡ã«ã¤ãã¦ãæ°ããå¦ã¶ãã¨ã¯ãã¾ãããã¾ãããHotwireèªä½ãRailsã®ã¨ã³ã·ã¹ãã ã®ä¸é¨ã§ãã£ã¦ãRailsã§ä½¿ã£ã¦ãããã¥ã¼æ§ç¯ã®ããã®ã©ã¤ãã©ãªããã®ã¾ã¾ä½¿ãã¾ãã
éçºã³ã¹ããä½ã
æ¢åã®Railsã¢ããªã®ã³ã¼ããå°ãä¿®æ£ããã ãã§SPA風ã«ã§ãã¾ãããã¢1ãããã¢2ã«ããã®ã«ãï¼è¦ãç®ã®ä¿®æ£ãé¤ãã¨ï¼æ°è¡ããä¿®æ£ãã¦ãã¾ããã
WebSocketã¯å¿ é ã§ã¯ãªã
èªåã¯èª¤è§£ãã¦ããã®ã§ãããWebSocketã¯å¿ é ã§ã¯ããã¾ãããTurbo StreamsãWebSocketï¼ActionCableï¼ã§ã使ããã¨ããã ãã§ããWebSocketã使ããã«ãfetchãªã¯ã¨ã¹ãã«å¯¾ãã¦Turbo Streamsãã¬ã¹ãã³ã¹ãããã¨ãå¯è½ã§ããå¤ãã®ã¢ããªã±ã¼ã·ã§ã³ã¯ããã§ååã§ããããWebSocketã¯ãã£ããã®ããã«ãªã¢ã«ã¿ã¤ã æ§ãå¿ è¦ãªæã«ã ã使ãã¾ãã
WebSocketãå¿ é ã¨ãªãã¨èãããã¨ãå¢ãã¦å¤§å¤ããã ãªãã¨æã£ã¦ããã®ã§ãWebSocketãªãã§ä½¿ããã®ã¯ãããããã§ãã
è¾ãã£ãç¹ã»è¾ããªããããªç¹
Hotwireã使ã£ã¦ã¿ã¦è¾ãã£ãã»è¾ããªãããã ã¨æããç¹ã¯ä»¥ä¸ã®ã¨ããã§ãã
DOMæ´æ°æã«ã¬ã¹ãã³ã¹ãå¾ ããªãã¨ãããªã
Hotwireã¯ãµã¼ãã¼ãµã¤ãã§ã¬ã³ããªã³ã°ãè¡ãã¾ãããã®ããDOMãæ´æ°ããéã«ã¯ãå¿ ããµã¼ãã¼ããã®ã¬ã¹ãã³ã¹ãå¾ ã¤ãã¨ã«ãªãã¾ããReactã§ããã°stateãæ´æ°ããã ãã§æ¸ããããªå ´åã«ããã¬ã¹ãã³ã¹ãå¾ ã£ã¦ããDOMãæ´æ°ãã¾ããDBã®ãã¼ã¿ãæ´æ°ããå ´åããã¬ã¹ãã³ã¹ãå¾ ã£ã¦ããDOMãæ´æ°ãã¾ãã楽観çãªæ´æ°ã¯ã§ãã¾ããï¼ä¸å¿Stimulusã使ãã°å®ç¾ã§ãã¾ãããã³ã¹ãçã«ã§ããã ãTurboã«ä»»ããã®ãè¯ãããã§ãï¼ã
é«ãå¿çæ§ãå¿ è¦ãªå ´åã«ã¯ãHotwireã¯ãããã»ããè¯ãããã§ãã
SPAã®ã¦ã¼ã¶ã¼ä½é¨ã¨ã¯ã ãã¶éã
Hotwireã¯SPA風ã¨å¼ã°ããããã¾ãããNextã®ãããªSPAãæå¾ ããã¨è£åããã¾ããReactãNextã§ã§ãããã¨ã®å¤ããHotwireã§ã¯ã§ãã¾ããã
Hotwireã使ã£ã¦ã¿ãã¨ãããã¯SPAã¨ããããããç´ ã®Railsãã«è¿ããã®ã§ãç´ ã®Railsã«æ©è½ã+αãããããªãã®ã ã¨æãã¾ãããå ·ä½çã«ã¯ç´ ã®Railsã«å¯¾ãã¦ãJSãªãã§ç»é¢é·ç§»ããã«CRUDã§ããããã«ãã¦ï¼Turboï¼ãJSããçDOMã触ãããã®ã¬ã¼ã«ãç¨æããï¼Stimulusï¼ãã®ãã¨ããã¤ã¡ã¼ã¸ã§ããå®éã«ã¯ä»ã«ãè²ã ãªãã¨ãã§ãã¾ãããã³ã¢ãªé¨åã¯ãããªã®ããªã¨ç解ãã¾ãããç»é¢è¨è¨ãRailsã¨åããCRUDããã¼ã¹ã«ãããã®ã«ãªããSPAã®ãããªãã¢ããªã±ã¼ã·ã§ã³ãã¨ããæãã®ãã®ã¨ã¯ã¡ãã£ã¨éãã¨æãã¾ããï¼å®éã«ã¯ä½ãè¾¼ã¿æ¬¡ç¬¬ã§ãããã Railsã®ããæ¹ã大ããå¤ãããã®ã§ã¯ããã¾ãããRailsã®ããæ¹ããé¢ããã»ã©ãHotwireã®è¯ããæ¶ãã¦ããã¾ãï¼ã
èªåãé¢ããæ¡ä»¶ã ã¨ããã§ååãªãã¨ãã»ã¨ãã©ã§ãã¾ãã«ãããããã®ã欲ããã£ãã®ã§ãèªåã«ã¯ããã¿ãªã§ããããã ãReactãNextã§å®ç¾ã§ãããããªã¦ã¼ã¶ã¼ä½é¨ã¨ã¯å·®ãããã¾ãã
SPAã®2å²ã®å´åã§8å²ã®å©çãåãã«è¡ãã®ãHotwireã ã¨æãã¾ãï¼å®éã«8å²ãå¾ããããã¯ãããã¾ããï¼ãTurboã使ã£ã¦SPA風ã«ããã®ã¯ã¨ã¦ãç°¡åã§ãã社å åãã®ç®¡çç»é¢ã®ãããªãã®ã§ããã°ãHotwireã§ååã§ããã§ãä¸å®ä»¥ä¸ã®ã¦ã¼ã¶ã¼ä½é¨ãå®ç¾ãããã¨æã£ãããHotwireã§ã¯è¶³ããªããªãå¯è½æ§ãããã¾ãã
Hey.comã¯Hotwireã§ä½ããã¦ãã¾ãããã以ä¸ã®ãã®ãå¿ è¦ãã©ããï¼ãã²ã¨ã¤ã®ç®å®ã«ãªãããã§ãã
Herokuã使ãã¥ãã
Hotwireã¯DOMæ´æ°æã«ã¬ã¹ãã³ã¹ãå¾ ã¤å¿ è¦ããããããã¬ã¤ãã³ã·ã®å½±é¿ãã¢ãã«åãã¾ãããã¢ã¢ããªã®ãã¹ãã£ã³ã°ã«ã¯Herokuãå©ç¨ãã¦ãã¾ããHerokuã¯æ±äº¬ãªã¼ã¸ã§ã³ããªãããUSãªã¼ã¸ã§ã³ãå©ç¨ãã¦ããã®ã§ãããæ¥æ¬ããã®ã¢ã¯ã»ã¹ã ã¨200msç¨åº¦ã®ã¬ã¤ãã³ã·ãçºçãã¾ããé常ã®ç»é¢é·ç§»ã ã¨ï¼èªåãé¢ããæ¡ä»¶ã§ã¯ï¼è¨±å®¹ç¯å²ã«ãªããã¨ãå¤ããã§ãããHotwireã使ã£ã¦ç»é¢ã®ä¸é¨ãæ´æ°ããå ´åã«ã¯ã¡ãã£ã¨è¨±å®¹ã§ããªãé ãã ã¨æãã¾ãã
ãã¡ãã¯ãã¢2ã®ã¢ããªãHerokuã§åããããã®ã¨ããã¼ã«ã«ã§åããããã®ã¨ã®æ¯è¼ã§ãã
ãã¢2ã触ã£ã¦ãããã¨ãããã¾ããã許容ã§ããªãé ãã§ãã
Herokuã¯ãã使ã£ã¦ããã®ã§ãããã¯æ®å¿µã§ããHotwireã使ããªãæ±äº¬ãªã¼ã¸ã§ã³ããããã¹ãã£ã³ã°ãµã¼ãã¹ã使ãããã¨ããã§ããPaaSã ã£ããRender.comã¨ãããµã¼ãã¹ãå®ãã¦ã使ããããã¦ãæ±äº¬ãªã¼ã¸ã§ã³ã«å¯¾å¿äºå®ã¨ããåãèããã®ã§ã試ãã¦ã¿ããã¨æãã¾ããä»ã«ãè²ã è¯ããããªPaaSãããã¿ããã§ãâ
ãã¨Hotwireã¨ã¯ç´æ¥é¢ä¿ãªãã®ã§ãããRails7ããimportmap-railsãããã©ã«ãã«ãªã£ã¦ãwebpackçã®ãã³ãã©ã¼ã使ããã«ES6ã®JSãã¡ã¤ã«ããã®ã¾ã¾é ä¿¡ããããã«ãªãã¾ããããã®éã«å¤ãã®å°ããªãã¡ã¤ã«ãéä¿¡ãããã¨ã«ãªãã®ã§HTTP/2ãå©ç¨ããã®ã§ãããHerokuã¯HTTP/2ããµãã¼ããã¦ãã¾ããããããã¡ãã£ã¨Herokuã使ãã¥ããçç±ã«ãªãã®ããªãã¨æãã¾ãããã ãã¡ãã«é¢ãã¦ã¯ãimportmap-railsã®ä»£ããã«jsbundling-railsã使ã£ã¦ãã³ãã«ããã¨ããHerokuã®å段ã«CDNãç½®ãã¨ãããã°è§£æ±ºãããã§ãã
TypeScriptã使ãã¥ãã
Hotwireã§ãTypeScriptã使ãã¾ãããã¡ãã£ã¨ä½¿ãã¥ããã§ãã
ã¾ãStimulus + TSã ã¨targetãvalueçã®ããããã£ã®åãèªåã§å®£è¨ããªãã¨ãããªãã®ã§ãããã¾ãTSã®æ©æµãåãããã¦ããªãæãããã¾ãã
ããã«Rails7ããimportmap-railsãããã©ã«ãã«ãªã£ã¦ããã©ã³ã¹ãã¤ã«ã»ãã³ãã«ã®ããã»ã¹ããªããªããES6ããã®ã¾ã¾ä½¿ãããã«ãªãã¾ãããå¥ã«importmap-railsã使ããªããã°ããã ããªã®ã§ããããã£ãããªãDHHããããã®ããæ¹ã§ããããæ°æã¡ã§ãã
ãã¨Hotwireã使ãã¨ãã¸ãã¯ããµã¼ãã¼ãµã¤ãã«å¯ã£ã¦JSã¯æ¥µç«¯ã«å°ãªããªãã®ã§ãããããTSã使ãå¿ è¦æ§ãä½ãã¨ãããã¨ãããã¾ãã
Railså´ãTSã使ããã¨ãããã¾ãèãã¦ããªããããªé°å²æ°ãæããã®ã§ãç¾å®çã«ã¯Hotwireã使ãéã«ã¯TSã¯ä½¿ããªããã¨ãå¤ãã®ããªã¨æãã¾ãã
Stimulusãé£ãã
Turboã¯ä½¿ããããã®ã§ãããStimulusã¯é£ããã¨æãã¦ãã¾ããæ£ç´ãä»ã®ã¨ããStimulusãä¸æã使ãã¦ããæãããã¾ããã
Stimulusã使ãéã®ã³ãã¯ãStimulusã³ã³ããã¼ã©ã¼ããã¼ã¸åä½ã§ã¯ãªãæ©è½åä½ã§ä½ããã¨ã ããã§ãããã¼ã¸ã«å¯¾å¿ãã大ããªã³ã³ããã¼ã©ã¼ã1ã¤ããã®ã§ã¯ãªããæ©è½ã«å¯¾å¿ããåå©ç¨å¯è½ãªå°ããªã³ã³ããã¼ã©ã¼ã沢山ç¨æãã¾ããããã¦ããããã®ã³ã³ããã¼ã©ã¼ãçµã¿åããã¦ã³ã³ãã¼ãã³ãï¼ã¨ããæ¦å¿µã¯ããã¾ãããï¼ãä½ã£ã¦ããã¤ã¡ã¼ã¸ã§ãããããæèããããã«ãªã£ã¦ãããå°ãã³ã¼ãããã·ã«ãªãã¾ããã
Stimulusã¯ããã¥ã¡ã³ããèªãã§ä½¿ãã ããªãç°¡åãªã®ã§ãããâã®ãµã¤ããèªããªã©ãã¦è¯ãæ¸ãæ¹ãæ¼ããã¦ãããªãã¨ã容æã«ã¤ããã³ã¼ããçã¿åºãã¾ãã
ãã¨Hotwireã使ãéã«ã¯Stimulusï¼ã¨ãããJSï¼ãã§ããã ãæ¸ããã«ããµã¼ãã¼ãµã¤ãã«ãã¸ãã¯ãå¯ãã¦Turboã§å¦çããã¨ããã®ããã¤ã³ãããªã¨æãã¾ããJSãæ¸ãéãå¢ããã»ã©Hotwireã®è¯ããæ¶ãã¦ãããReact + TSã使ããããªãã¾ãã
æ¥æ¬èªã®æ å ±ãå°ãªã
æ¥æ¬ã§ã¯ã¾ã ããã¾ã使ããã¦ããªãããã§ãæ¥æ¬èªã®æ å ±ãå°ãªãæ¥æ¬èªã§ã®å¦ç¿ãé£ããã§ããRailsã®ããã©ã«ãã«æ¡ç¨ããã¦ããã¾ã ãããªã«æéãçµã£ã¦ããªãã®ã§ãããããå¢ãã¦ããã®ããªï¼ã¨æãã¾ãã
å ¥éæ¸ãæ¸ãã¾ãããç¡æã§ããHotwireã®æåã®1åã¨ãã¦èªãã§ããã ãã¾ãã¨å¹¸ãã§ãðââï¸
é»éè¡æ
ï¼ã¡ã¿ããã°ã©ãã³ã°ã®è©±ã§ã¯ããã¾ãããï¼
Turbo Streamsã使ãDOMãæ´æ°ããå ´åãã³ã³ããã¼ã©ã¼ã¨ãã¥ã¼ã¯ãããªæãã«ãªãã¾ãã
# app/controllers/cats_controller.rb def update if @cat.update(cat_params) render # update.turbo_stream.erbãrender else render :edit, status: :unprocessable_entity end end
<%# app/views/cats/update.turbo_stream.erb %> <%= turbo_stream.replace @cat %>
catã®æ´æ°æåæã«ã¯update.turbo_stream.erb
ãrenderãã¦ãã¾ããupdate.turbo_stream.erb
ã¯ä»¥ä¸ã®ãã解éããã¾ãã
<%# å é¨çã«ã¯ãã¼ã·ã£ã«ã®renderãè¡ããã %> <%= turbo_stream.replace @cat do %> <%= render partial: "cats/cat", locals: { cat: @cat } %> <% end %>
ããã¦ããã¯ä»¥ä¸ã®ãããªHTMLã«ãªãã¾ãã
<turbo-stream action="replace" target="cat_1"> <template> <!-- ãã¼ã·ã£ã«ã®renderçµæ --> </template> </turbo-stream>
æçµçã«<turbo-stream>
ã«ã¹ã¿ã è¦ç´ ããã©ã¦ã¶å´ã§è©ä¾¡ããã¦ã<template>
å
ã®è¦ç´ ã§#cat_1
ã®è¦ç´ ãç½®æãã¾ãã
ã¡ãã£ã¨ç¬ç¹ãªããæ¹ã§ãåè¦æã¯ä½ãèµ·ãã¦ããã®ããããã¾ããã§ãããSJRï¼Server-generated JavaScript Responsesï¼ã¨ãããupdate.js.erb
ã®ãããªãã¡ã¤ã«ãç¨æãã¦ãJSãERBã§ä½ã£ã¦ã¬ã¹ãã³ã¹ããã¨ããæ¹æ³ãããã¾ããããããã«ä¼¼ãä¸æè°æãããã¾ããæ
£ããã¨Railsã®ã¬ã¼ã«ã«ä¹ãã¤ã¤ãã¼ã·ã£ã«ãç°¡åã«ä½¿ãåãã¦ããæããªã®ã§ãããæåã¯ã¡ãã£ã¨æ¸æãããããã¾ããã
Turbo Streamsã«éãããHotwireã¯åé¡è§£æ±ºã®ã¢ããã¼ããç¬ç¹ãªæããããã®ã§ãã¡ãã£ã¨é»éè¡ããæãããã¨ãããã¾ãã
å¯è±ªç
Hotwireã®Turbo Framesã¯å¯è±ªçï¼ã¨ããã®ããªï¼ï¼ãªã¢ããã¼ãã§SPA風ã®æåãå®ç¾ãã¾ãã
ãã¢2ã§ã¯ãã¼ã¸ãã¼ã·ã§ã³ã«Turbo Framesãå©ç¨ãã¦ãã¾ãããã¼ã¸ãã¼ãæã«ç·ç·ã§å²ã£ãæ¤ç´¢çµæï¼ä¸è¦§ï¼ã®é¨åã ããæ´æ°ãã¾ãã
ãã®éã«index.html.erb
ãã³ãã¬ã¼ããåå©ç¨ããã®ã§ãããindex.html.erb
ãã¬ã³ããªã³ã°ããã®ã¯æ¤ç´¢çµæã®é¨åã ãã§ã¯ããã¾ãããæ¤ç´¢ãã©ã¼ã é¨åãå«ãã¦HTMLã丸ãã¨ã¬ã³ããªã³ã°ãã¾ãããããæ¤ç´¢ãã©ã¼ã é¨åã¯ã¬ã³ããªã³ã°ããã¬ã¹ãã³ã¹ããã¾ãããã¯ã©ã¤ã¢ã³ãå´ã§ä½¿ãããã«æ¨ã¦ããã¾ããå®ç¨ä¸ã¯åé¡ã«ã¯ãªãã¾ããããã¡ãã£ã¨ç¡é§ãªå¦çããã¦ããããªæãããã¾ãã
ãã ããã®ç¡é§ã®ãããã§ãæ¢åã®Railsã¢ããªã«1è¡ã³ã¼ããå ããã ãã§ãç»é¢ãé¨åæ´æ°ã§ããããã«ãªãã¾ããå¤å°ã®ããã©ã¼ãã³ã¹ããµã¼ãã¼ãªã½ã¼ã¹ãç ç²ã«ãã¦ã§ããåé¡ãã·ã³ãã«ã«è§£æ±ºãã¦ãçç£æ§ã¨ä¿å®æ§ãåãã«è¡ãã®ãHotwireçãªã¢ããã¼ããªãã ã¨ç解ãã¾ããã
partialã ããã«ãªã
åºæ¬çã«ã¯DOMæ´æ°ã«ã¯partialã使ãã®ã§ãå¤ç¨ããã¨partialã ããã«ãªãã¾ãããã¾ããã¨æ´çããæ¹æ³ãç¥ããã......
ãµã¼ãã¼ã®ãªã½ã¼ã¹ãé£ã
æ¯åãµã¼ãã¼ãµã¤ãã§ã¬ã³ããªã³ã°ããã®ã§ããµã¼ãã¼ã®ãªã½ã¼ã¹ãé£ãã¾ãã
åæ¥ã¯é£ãã
ããã¯ã¨ã³ãã¨ããã³ãã¨ã³ããå¯çµåããã®ã§ãåæ¥ããã®ã¯é£ããã§ãã
ãã¨ã¢ãã¤ã«ã¢ããªã¯åºæ¬WebViewã«ãªãã¾ãããã¡ããåæ¥ããã®ã¯é£ããã§ãã
ããã¯1人ã®Railsã¨ã³ã¸ãã¢ãä¸ããä¸ã¾ã§å ¨é¨ãã§ãããã¨ãããã¨ã®è£è¿ãã§ããã©ã£ã¡ãè¯ããã¯ä½ããã®ã»è¦æ¨¡ã»ãªã½ã¼ã¹çã«ããã¨æãã¾ãã
å¾ããSPAã«ããã®ã¯è¾ãã
è¦æ¨¡ã大ãããªã£ããããã¯ã¨ã³ãã¨ããã³ãã¨ã³ããåãã¦ãã£ã¤ãSPAã«ããããã¨ãããã¨ãããã¾ãããã®æã«Hotwireãå¥ããã¦SPAã«ããã¨ããã®ã¯ã¡ãã£ã¨è¾ãããã§ãã
Hotwireã使ã£ãRailsã¢ããªã¯ç´ ã®Railsã¢ããªã¨ãããªã«å¤§ããå¤ããã¾ããããªã®ã§ã³ã¹ãçã«ã¯ç´ ã®Railsã¢ããªãSPAåããã®ã¨ãã¾ãå¤ãããªãã¨æãã¾ãããã ãçµå±ããã³ãã¨ã³ãã¨ããã¯ã¨ã³ããåãããã ã£ããããªãã§Hotwire使ã£ããã ï¼æåããReactã«ãã¦ããã°ããã£ãã®ã§ã¯ï¼ã¨ãªããããªæ°ããã¾ãã
åãã¦ããã±ã¼ã¹
Hotwireã«åãã¦ããã®ã¯ä»¥ä¸ã®ãããªã±ã¼ã¹ã«ãªãã®ããªãã¨æãã¾ãã
ç´ æ´ãªUI
CRUDããã¼ã¹ã«ããç´ æ´ãªUIãä½ãã®ã«åãã¦ãã¾ãã
JSããã£ã¤ã使ã£ããªãããªUIãä½ãã®ã«ã¯åãã¦ãã¾ããã
Hey.com以ä¸ã®ãã®ãå¿ è¦ãã©ããï¼ãã²ã¨ã¤ã®ç®å®ã«ãªãããã§ãã
ãµã¼ãã¼ãµã¤ãã¨ã³ã¸ãã¢ã ãã®å°è¦æ¨¡ãªãã¼ã
Hotwireã使ãã¨ãµã¼ãã¼ãµã¤ãã ãã«éä¸ã§ããããã«ãªãã¾ãããµã¼ãã¼ãµã¤ãã¨ããã³ãã¨ã³ãã®åæ¥ã¯ãªããªããJSã¯ãµã¼ãã¼ãµã¤ãã¨ã³ã¸ãã¢ãæ¸ããã®ã«ãªãã¾ãããã®ãããããã³ãã¨ã³ãã¨ã³ã¸ãã¢ãããªããããªããµã¼ãã¼ãµã¤ãã¨ã³ã¸ãã¢ã ãã§æ§æãããå°è¦æ¨¡ãªãã¼ã ã«åãã¦ãã¾ãã
å°è¦æ¨¡ãªã¢ããªã±ã¼ã·ã§ã³ã ã¨ãä¸äººã®éçºè ãããã³ãã¨ã³ãã¨ããã¯ã¨ã³ãã®ä¸¡æ¹ã触ããã»ããé½åãè¯ãã§ããéã«å¤§è¦æ¨¡ãªå ´åã¯åæ¥ããã»ããé½åãè¯ããã¨ãå¤ããHotwireã¯åãã¦ããªãã®ããªã¨æãã¾ãï¼å¤§è¦æ¨¡ãªãã¼ã ãçµé¨ãããã¨ããªãã®ã§æ¨æ¸¬ã§ããï¼ã
Railsã«æ £ãã¦ãããã¼ã
Hotwireã使ãã¨Railsã®è³ç£ããã«ã«æ´»ããã¾ããRailsã«æ £ãã¦ãããã¼ã ãHotwireã使ãã¨ãç´ ã®Railsã¢ããªãéçºããã®ã«æ¯ã¹ã¦ãéè²ãªãé度ã§SPA風ã®ã¢ããªã±ã¼ã·ã§ã³ãéçºã§ãã¾ãï¼å®éã¯ä½ãè¾¼ã¿æ¬¡ç¬¬ã§ãããã¢ç¨åº¦ã®ãã®ã§ããã°ç´ ã®Railsã§ä½ãã®ã¨ã»ã¨ãã©å´åã¯å¤ããã¾ããï¼ã
管çç»é¢
ããããã¯å ·ä½çãªã±ã¼ã¹ãèãã¦ã¿ã¾ãã
ä½ããã®ã¨ãã¦ã¯ãHotwireãä¸çªåãã¦ããã¨æãã®ã管çç»é¢ã§ãã管çç»é¢ã¯ãããªã«éçºãªã½ã¼ã¹ããããªãããã©ããããããã¤ã³ã¿ã©ã¯ãã£ãã§ãã£ã¦æ¬²ãããæ©è½çã«ã¯CRUD + αç¨åº¦ã«ããã¾ãã¾ããHotwireã使ãã«ã¯ä¸åº¦ããã§ãã
Railsã®åè¨ä¼ç¤¾
çµç¹ã¨ãã¦ã¯ãRailsãã¡ã¤ã³ã«ãã¦ããåè¨éçºã®ä¼ç¤¾ã¯ã¨ã¦ãåãã¦ããã¨æãã¾ãã
Railsã¨ã³ã¸ãã¢ãå¤ãã¦æ¢åã®Railsã®è³ç£ãæ´»ãããããåæ¥ããªãå°è¦æ¨¡ãªãã¼ã ã«ãªããã¨ãå¤ãããç´ æ´ãªUIã§OKãªãã¨ãå¤ããã価å¤ãå±ãããã¨ã«ãã©ã¼ã«ã¹ã§ããããåè¨æ¡ä»¶ã®å¤ãã¯Hotwireåãã§ããå®éã«ä½¿ããã©ããã¯æ¡ä»¶æ¬¡ç¬¬ã¨ãªãã¾ãããå¤ãã®æ¡ä»¶ã§ãä¸åº¦ãããé¸æã«ãªãããããªããã¨æãã¾ãã
ã¹ã¿ã¼ãã¢ãã
èªåã¯ã¹ã¿ã¼ãã¢ããã®çµé¨ã¯ããã¾ããªããã§ãããAutifyã®è¿æ¾¤ããã®podcastãèãã¦ãHotwireã¯ã¹ã¿ã¼ãã¢ããã«ãåãã¦ãããã ãªã¨æãã¾ããã
Autifyã¯Railsããã¯ã¨ã³ã + Reactããã³ãã¨ã³ãã«ããSPAã®éçºãå§ããã®ã§ãããéçºé度ã®é¢ã§åé¡ãçãããããReactãæ¨ã¦ã¦Railsã®ã¿ã«ããããã§ããããã¦ããã³ãã¨ã³ãã¨ã³ã¸ãã¢ã®æ¹ãå ¥ç¤¾ããã¦ãããå¹æãé«ããã¼ã¸ããå¾ã ã«SPAåãå§ããããã§ãï¼è©³ããã¯Podcastãèãã¦ãã ããï¼ã
ã¹ã¿ã¼ãã¢ããã§ã¯ã§ããã ãéã価å¤ãå±ãããã¨ãæåªå äºé ã«ãªãã¾ããæéãããã¦ãªãããªUIãä½ãè¾¼ãã§ãã使ã人ãããªãã£ããæå³ãããã¾ãããæçµçã«SPAã«ããããã¨ããçç±ã§æåããSPAãä½ãã®ã¯ãå ´åã«ãã£ã¦ã¯ä»®èª¬æ¤è¨¼ã®ãµã¤ã¯ã«ãåãé度ãè½ã¨ãã¦ãã¾ãå¯è½æ§ãããã¾ãï¼ä½ããã®ãã¡ã³ãã¼ã®ã¹ãã«ã»ãã次第ã ã¨æãã¾ãï¼ãHotwireã¯æåã¯ç´ ã®Railsã¨åãããã«éçºãã¦ãå¾ä»ãã§æ®µéçã«SPA風ã«ä½ãè¾¼ãã§ããã¨ãããã¨ãå¾æã§ããåéãè½ã¨ããã«SPAã®æ©æµãåããããã®ã§ãéçºé度ã¨ï¼ããããã®ï¼ã¦ã¼ã¶ã¼ä½é¨ã®ä¸¡æ¹ãåãããã¹ã¿ã¼ãã¢ããã«ã¯è¯ãé¸æã«ãªãã¾ãã
ãã ãã¢ããªã®è¦æ¨¡ã大ãããªã£ããããã¯ã¨ã³ãã¨ããã³ãã¨ã³ããåãã¦SPAåãããã¨ããã±ã¼ã¹ãåºã¦ããã¨æãã¾ãããã®éã«Hotwireãå¥ããã®ã¯è¾ãããªã®ã§ãçµæçã«ä¸éå端ãªé¸æã¨ãªã£ã¦ãã¾ãå¯è½æ§ã¯ããã¾ãã
å人éçº
Hotwireã¯å人éçºã«ãåãã¦ãã¾ããä¸äººã§ããã¯ã¨ã³ãã¨ããã³ãã¨ã³ãã®ä¸¡æ¹ãæ¸ãã®ã¯ãªããªã大å¤ã§ãããHotwireã§ããã°ä¸äººã§ãåé¡ãªãéçºã§ãã¾ãã
åãã¦ããªãã±ã¼ã¹
Hotwireã«åãã¦ããªãã®ã¯ä»¥ä¸ã®ãããªã±ã¼ã¹ã«ãªãã¨æãã¾ãã
- ãªãããªUIãå¿ è¦
- é«ãå¿çæ§ãå¿ è¦
- ããã³ãã¨ã³ãã¨ããã¯ã¨ã³ããåæ¥ãããããªå¤§è¦æ¨¡ãªãã¼ã
- ãã¤ãã£ãã¢ããªãå¿ è¦ï¼Hotwireã ã¨åºæ¬WebViewã«ãªãï¼
Hotwireã¨åè¨ä¼ç¤¾
èªåã¯åè¨ã®çµé¨ãé·ãã§ãHotwireã¯Railsã®åè¨ä¼ç¤¾ã«ã¨ã¦ããããæè¡ã ã¨èãã¦ããã®ã§ãã¡ãã£ã¨åè¨ã¨Hotwireã®é¢ä¿ãæ·±å ããã¦ã¿ã¾ãã
HotwireããããªããªããRailsãããçç±ã¯æ¸ã£ã¦ãã
Hotwireã¯Reactï¼çã®ç¾ä»£ã®ããã³ãã¨ã³ãã®æè¡ï¼ã¨ã¯çéã®æ¹åãåããæè¡ã§ããRailsã¯Hotwireã®æ¹åã¸é²ãã§ããã¾ããã¤ã¾ãRailsã¯ç¾ä»£ã®ããã³ãã¨ã³ãã¨ã¯éæ¹åã¸é²ãã§ããã¾ããRailsããããªãHotwireãããããããéã«Hotwireããããªããªãããã¯ã¨ã³ãã«Railsãé¸ã¶çç±ã¯ï¼æ¢ã«æ¸ã£ã¦ãã¦ãã¾ãããä»å¾ã¾ãã¾ãï¼æ¸ã£ã¦ããã¾ãããªã®ã§Hotwireããã£ã¦ãããã©ããã¨ããåé¡ã¯ãå®ã¯ãä»å¾ãä¼ç¤¾ã¨ãã¦Ruby/Railsããã£ã¦ãããã©ããã¨ããåé¡ã¨å¤§ããé¢ãã£ã¦ãããã ã¨æãã¾ãã
Reactããã£ã¦ãããã人ããããã¨ãHotwireã¯åãå ¥ããããªãæãã«ãªããã ããã¨æãã¾ãããã®ããReactãæ¢ã«ã¬ãããªä½¿ã£ã¦ãçµç¹ã§ã¯ãHotwireã¯æ¡ç¨ãã¥ãããã§ããHotwireãä¸éå端ã«æ¡ç¨ããã¨ãTurbolinks + Stimulusãããã ã£ãããã«ãçµç¹å ã§è² åµã¨ãã¦æ±ãããããã«ãªã£ã¦ãã¾ãå¯è½æ§ãããã¾ãããªã®ã§ãHotwireãæ¡ç¨ãããªããçµç¹ã¨ãã¦Hotwireããã£ã¦ãããï¼ä»å¾ãRuby/Railsããã£ã¦ãããï¼ã¨ãªãã®ãçæ³ãªã®ããªã¨æãã¾ããRailsã¡ã¤ã³ã®åè¨éçºã®ä¼ç¤¾ã ã¨ãã®ææ決å®ãããããããªã®ã§ããã®ç¹ã§ãåãã¦ãããã§ãã
Rails + Reactã®ã¤ãã
åè¨ã§ã¯åæ¥ããã«1人ã®ã¨ã³ã¸ãã¢ãããã¯ã¨ã³ãããããã³ãã¨ã³ãã¾ã§å ¨é¨ããã±ã¼ã¹ãå¤ãã¨æãã¾ãããã®æã«Rails + Reactï¼å ¸åçã«ã¯Nextã«ããSPAï¼ãæ¡ç¨ãããã¨ãå¤ãã¨æãã¾ããããã®æ§æã«ã¯ã¤ãããæãã¦ãã¾ãã
ä»ã¾ã§èªåãè¦ã¦ããRails + Reactã®æ¡ä»¶ã¯ããã¾ããã¾ããã£ã¦ããªããã¨ãå¤ãã£ãã§ããããã¯ã¨ã³ãã¨ããã³ãã¨ã³ãã®ä¸¡æ¹ãä½ãå¿ è¦ããããéçºé度ã®é¢ã§åé¡ãçãã¦ãã¾ãããããã«éçºé度ã®åé¡ã«å ãã¦ãè¤éããå¢ããã¨ã§ãããã°ãé£ãããªããå¤ãã®ãã°ãçã¿åºããããã©ã¼ãã³ã¹æ¹åãé£ãããªã£ã¦ãã¾ãããã¦ã¼ã¶ã¼ä½é¨ãè¯ãããããã«Reactãæ¡ç¨ãã¦ããã¯ããªã®ã«ãã¦ã¼ã¶ã¼ä½é¨ãæªããã¦ãããã¨ããããã¾ããã
ããã¯Reactã®åé¡ã§ã¯ãªãããã¼ã æ§æã¨æè¡é¸å®ã®åé¡ã§ããèªåãé¢ãã£ã¦ããæ¡ä»¶ã¯ãRailsã¨ã³ã¸ãã¢ã ãããæ§æãããå°è¦æ¨¡ãªãã¼ã ã§ãããããããã¼ã ã ã¨ããã¯ã¨ã³ãã¯Railsãããã§ãããã³ãã¨ã³ãã©ããããï¼ã¨ããæµãã«ãªãã¾ããããã¯ã¨ã³ããRailsã§ããã°ãMPAããSPAã®æ¹ãè¤éã«ãªãã³ã¹ããé«ããªãã®ã¯æããã§ãã
ã§ããããã¯ã¨ã³ããããã³ãã¨ã³ãã¨åããTypeScriptãæ¡ç¨ããã°ããããªã§ããªãã®ããªï¼ã¨æã£ããããã¾ããè¨èªãçµ±ä¸ããã°ã³ã³ããã¹ãã¹ã¤ããããªããªãããåããã¸ãã¯ãå ±æã§ãã¾ããã¤ã¾ãReactãã¤ããã£ãããããªããRails + Reactãã¤ããã£ãããããªããã¨ããæ°ããã¦ãã¾ããå®éã«ä»äºã§TypeScript + React + Next + API Routes + Prismaã®ãããªæ§æã§å°è¦æ¨¡ãªSPAãä½ã£ãã®ã§ãããããã³ãã¨ã³ããããã¯ã¨ã³ããããããä½ãã¦ãããã§è¯ãããã¨ããæ°æã¡ã«ãªãã¾ãããé¢åãªé¨åã¯Nextãããæãã«ãã£ã¦ããã¾ããããªã«ããVSCode + TypeScriptã®çµã¿åããã«ããéçºä½é¨ãã¨ã¦ãè¯ãã¦ãããã³ãã¨ã³ãã¨ããã¯ã¨ã³ãã ãã¨è¨ãããå ¨é¨TSã§ããããããããã«æãã¾ããï¼API Routesã§ç ´ç¶»ããªããããªå°è¦æ¨¡ãªã¢ããªãä½ã£ãææ³ãªã®ã§ãè¦æ¨¡ã大ãããªãã¨è©±ãå¤ããããã§ã¯ããã¾ãï¼ã
ãã¨èªåãè¦ã¦ããRails + Reactã®æ¡ä»¶ããã¾ããã¾ããã£ã¦ããªãã£ãçç±ã®1ã¤ã¨ãã¦ãåç´ã«ReactãSPAã«æ £ãã¦ããªãã¨ãããã¨ã大ããã£ãã§ãï¼ã¨ããããããä¸çªå¤§ããªçç±ãªæ°ããã¾ãï¼ãããã¯ã¨ã³ãã¨ããã³ãã¨ã³ãã®ä¸¡æ¹ãå¦ã³ã¤ã¥ããã®ã¯ãªããªã大å¤ã§ããåºç¤ã¯æ¼ãããããã¨ãã¦ããã¨ã³ã·ã¹ãã ã¯ã©ãã©ãé²åãã¦ããã¾ããæ°ããæ å ±ã追ããããã ãã§ç²¾ä¸æ¯ã«ãªã£ã¦ãã¾ãããã®çµææè¡ã®æ·±å ããã§ããã«ãããã¯ã¨ã³ããããã³ãã¨ã³ããã©ã£ã¡ãä¸éå端ã¨ãããã¨ã«ãªããã¡ã§ãï¼ãªãã¾ããï¼ãããã³ãã¨ã³ããå®åã¬ãã«ã§ãã£ã¦ããã«ã¯ç¸å½ãªå¦ç¿ãå¿ è¦ã§ããNodeãæ·±ãç¥ããã«ãNodeã®çµé¨ãç©ã¾ãã«ãããã³ãã¨ã³ãããããã¨ã«ã¯ã ãã¶å³ãããæãã¦ãã¾ããããã¯ã¨ã³ãã«Nodeï¼TSï¼ãæ¡ç¨ããã¨è¨èªãã¨ã³ã·ã¹ãã ã®å¦ç¿å¹çãæ大åã§ãããããã¹ã¼ãã¼ãã³ã§ãªãã¨ãããã¯ã¨ã³ãã¨ããã³ãã¨ã³ãã®ä¸¡æ¹ãæ·±ãå¦ç¿ãã¦ãããããã«ãªãã®ããªã¨æãã¾ãã
ããã¯ã¨ã³ããTSã«ããã¨ããã®ã¯ã¨ã¦ãè¯ãããã§ããTSã¯ããã¯ã¨ã³ããããã³ãã¨ã³ãã ãã§ãªãããµã¼ãã¼ã¬ã¹ãã¢ãã¤ã«ã¢ããªããã¹ã¯ãããã¢ããªï¼ã¨ãããGUIå ¨è¬ï¼ãªã©ããããåéã§æ´»èºãã¦ãããã®ã§ããªã½ã¼ã¹ä¸è¶³ã®çµç¹ã«ãåªãããã§ããHotwireã®ããã«ãµã¼ãã¼ãµã¤ãã¬ã³ããªã³ã°ã®ã¿ã¨ããå¶ç´ã«ãããã¦ã¼ã¶ã¼ä½é¨ã®éçãããã¾ãããåãããã¾ããããã³ãã¨ã³ãã®æµãã§ä»å¾ã¾ãã¾ãé²åãã¦ãããã¨ã¯ç¢ºå®ã§ãããå®ã¯ãã£ã¡ã®æ¹åæ§ã®ãè¯ãããããªããã¨ããæ°ããã¦ãã¾ãã
åæ¥ã§ããè¦æ¨¡ãªãRails + Reactã§ãåé¡ã«ãªããªãã®ããªã¨æãã¾ãããã ãä¸äººã§å ¨ã¦ãæ å½ãããããªå ´åã«ã¯ãRails + Reactã ã¨ãRailsã¨Reactã®ã©ã¡ãã®è¯ãã殺ãã¦ãã¾ã£ã¦ããããã«æãã¾ããRails + Hotwireã§ãReact + Nodeï¼TSï¼ã§ãããã®ã§ãããã©ã¡ããã«å¯ãããæ°æã¡ã§ãããµã¼ãã¼ãµã¤ãéè¦ãªãRails + Hotwireã§ãã¯ã©ã¤ã¢ã³ããµã¤ãéè¦ãªãReact + Node(TS)ã使ãã¨ä½ãããããã§ãããã¾ãã©ã¡ããé¸ãã§ããã©ã³ã¹ãã対å¿ã§ããã¨æãã¾ãã
Railsã®åè¨ä¼ç¤¾ã¯Hotwireãè¯ããã
ã¨ã¯ãããRailsã®åè¨ä¼ç¤¾ã«ã¯Hotwireãæ¨ãããã§ãã
èªåãé¢ãã£ãåè¨æ¡ä»¶ã«é¢ãã¦ã¯ãHotwireã§ååãªãã®ãã»ã¨ãã©ã§ãããããã©ã¼ãã³ã¹ã¯ããã¦ãSQLãããã«ããã¯ã§ãããæ°ç¾msã¨ããå ´åã«ãã£ã¦ã¯1000ms以ä¸ãããå ´åãããã¨ãããããã¬ãã«ã§ãããããæ¹åãã¦ããã¦ããã°ãåºãªãããã«ãã¦ãããããã®ã¦ã¼ã¶ã¼ä½é¨ãå®ç¾ã§ããã°ããã¨ã¯ä¾¡å¤æä¾ã®é度ãéè¦ããã¾ãã
çµç¹ã«ã¯Railsã¢ããªã沢山ãããRailsãå¾æãªã¨ã³ã¸ãã¢ã沢山ãã¦ãRailsã®è³ç£ãæºã¾ã£ã¦ãã¾ããRailsã®åè¨ä¼ç¤¾ã®å ´åã¯ãRuby/Railsãããã¦ããã¯ã¨ã³ããNodeï¼TSï¼ã«ãã¦ããæ¹åæ§ããã¯ãHotwireãæ¡ç¨ããæ¹åæ§ã®ã»ããè¯ãããããªããã¨ããæ°ããã¾ãã
Railsã¯æè¡çãªç®æ°ããã¯ããã»ã©ãªãããããã¾ãããããµã¼ãã¼ãµã¤ããéè¦ãªã¢ããªã±ã¼ã·ã§ã³ã§ã価å¤æä¾ã«ãã©ã¼ã«ã¹ãããã®ã§ããã°ãä»ã§ãè¯ãé¸æã ã¨æãã¾ããããã¦Railsã使ããªãHotwireã¯æé«ã®ç¸æ¹ã«ãªãã¾ãã
ã¾ã¨ã
ãããé·ããªã£ã¦ãã¾ã£ãã
Hotwireã¯åãä¸åããã¯ã£ããããæè¡ã ã¨æãã¾ããHotwireãè¯ãé¸æã«ãªããã©ããã¯ã±ã¼ã¹æ¬¡ç¬¬ã§ããReactçã®ç¾ä»£ã®ããã³ãã¨ã³ãæè¡ã使ã£ã¦ãã¦ãéçºé度ã®é¢ãªã©ã§èª²é¡ãæãã¦ããªãã®ã§ããã°ãããã¦Hotwireã使ãå¿ è¦ã¯ãªãã®ããªã¨æãã¾ãï¼ãã¶ã1人ã®Railsã¨ã³ã¸ãã¢ãä¸ããä¸ã¾ã§å ¨é¨ãããã¨æã£ãæã«ããã®èª²é¡ãæãããããã ããã¨æãã¾ãï¼ã
å人çã«ã¯Hotwireã¯å¤ãã®Railsåè¨æ¡ä»¶ã§ãä¸åº¦ãããé¸æã«ãªãããã ã¨æãã®ã§ãåè¨ä¼ç¤¾ã®æ¹ã«ã¯ãã²Hotwireã§éãã§ã¿ã¦ã»ãããªãã¨æãã¾ããã
åè
Stimulus 3 + Turbo 7 = Hotwire 1.0
Hotwire を 本番環境で使ってみた感想 - Speaker Deck
Modern web apps without JavaScript bundling or transpiling
Deviseå ¥é 64ã®ã¬ã·ã
- ç°å¢
- 第1ç« Deviseãã¯ãããã
- 第2ç« ã¢ã¸ã¥ã¼ã«ã使ã
- 003 ã¢ã¸ã¥ã¼ã«ã¨ã¯ï¼
- 004 Registerableã¢ã¸ã¥ã¼ã«
- 005 Database Authenticatableã¢ã¸ã¥ã¼ã«
- 006 Rememberableã¢ã¸ã¥ã¼ã«
- 007 Recoverableã¢ã¸ã¥ã¼ã«
- 008 Validatableã¢ã¸ã¥ã¼ã«
- 009 Confirmableã¢ã¸ã¥ã¼ã«
- 010 Trackableã¢ã¸ã¥ã¼ã«
- 011 Timeoutableã¢ã¸ã¥ã¼ã«
- 012 Lockableã¢ã¸ã¥ã¼ã«
- 013 Omniauthableã¢ã¸ã¥ã¼ã«
- 第3ç« ãã¥ã¼ãã«ã¹ã¿ãã¤ãºãã
- 第4ç« ã³ã³ããã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºãã
- 第5ç« ã¢ãã«ãã«ã¹ã¿ãã¤ãºãã
- 第6ç« ã«ã¼ãã£ã³ã°ãã«ã¹ã¿ãã¤ãºãã
- 025 deivse_forã§ã«ã¼ãã£ã³ã°ãå®ç¾©ãã
- 026 devise_forãã«ã¹ã¿ãã¤ãºãã
- 027 åå空éãæå®ãã
- 028 ç¬èªã®ã«ã¼ãã£ã³ã°ãå®ç¾©ãã
- 029 Deviseã®ã«ã¼ãã£ã³ã°ã0ããå®ç¾©ãã
- 030 ãã°ã¤ã³å¾ã¨ãã°ã¤ã³åã§rootã®ã«ã¼ãã£ã³ã°ãåãã
- 031 ãã°ã¤ã³å¾ã®ã¿ã¢ã¯ã»ã¹ã§ããã«ã¼ãã£ã³ã°ãå®ç¾©ãã
- 032 /users/sign_inã/users/loginã«å¤æ´ãã
- 第7ç« ã¡ã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºãã
- 第8ç« I18nãã«ã¹ã¿ãã¤ãºãã
- 第9ç« è¨å®ãã«ã¹ã¿ãã¤ãºãã
- 第10ç« ãã®ä»ã®ã«ã¹ã¿ãã¤ãºï¼Wikiã¾ã¨ãï¼
- 041 ãã¹ã¯ã¼ãå¤æ´æã«ãã°ã¢ã¦ããããªã
- 042 Deviseã«ç¬èªã®èªè¨¼æ¹æ³ï¼Strategyï¼ã追å ãã
- 043 ã²ã¹ãã¦ã¼ã¶ã¼æ©è½ãå®è£ ãã
- 044 ã¢ã«ã¦ã³ãåé¤ãè«çåé¤ã«ãã
- 045 管çè 権éãç¨æãã
- 046 emailã¨usernameã©ã¡ãã§ããã°ã¤ã³ã§ããããã«ãã
- 047 ãã¹ã¯ã¼ãå ¥åãªãã§ã¢ã«ã¦ã³ãæ å ±ãå¤æ´ãã
- 048 ãã¹ã¯ã¼ããbcrypt以å¤ã®æ¹æ³ã§ããã·ã¥åãã
- 049 ã¡ã¼ã«ã¢ãã¬ã¹å¤æ´æã«ãConfirmæ示ã¡ã¼ã«ãéä¿¡ãã
- 第11ç« Tips
- 第12ç« Deviseã®ã¨ã³ã·ã¹ãã
- 053 AnyLogin - ãã°ã¤ã³ã¦ã¼ã¶ã¼ãåãæ¿ãã
- 054 devise-i18n - ãã¥ã¼ãæ¥æ¬èªåãã
- 055 DeviseInvitable - æå¾
æ©è½ã追å ãã
- DeviseInvitableã使ã£ã¦ã¿ãã
- Invitableã¢ã¸ã¥ã¼ã«ã®ã³ã³ããã¼ã©ã¼ã¨ã«ã¼ãã£ã³ã°
- Invitableã¢ã¸ã¥ã¼ã«ã®ã¡ã½ãã
- Invitableã¢ã¸ã¥ã¼ã«ã®è¨å®
- ãã¥ã¼ãã«ã¹ã¿ãã¤ãºãã
- ã³ã³ããã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºãã
- Strong Parameterãã«ã¹ã¿ãã¤ãºãã
- I18nãã«ã¹ã¿ãã¤ãºãã
- åè
- 056 Devise Security - ã¨ã³ã¿ã¼ãã©ã¤ãºãªã»ãã¥ãªãã£ã¼æ©è½ã追å ãã
- 第13ç« Deviseå é¨ãç¥ã
- 第14ç« èªè¨¼gemã®æ¯è¼
- Deviseã®æ å ±æº
- ãã¼ãã·ã¼ã
ããã¯ããã£ã¨ã«ããã¼ããã£ã³ã Advent Calendar 2020ãã®1æ¥ç®ã®è¨äºã§ãã
ãã£ã¨ã«ããã¼ããã£ã³ã Part 1 Advent Calendar 2020 - Adventar
ãã£ã¨ã«ããã¼ããã£ã³ã Part 2 Advent Calendar 2020 - Adventar
ç°å¢
Ruby: 2.7.1
Rails: 6.0.3
Devise: 4.7.3
第1ç« Deviseãã¯ãããã
ð± Deviseã¯Railsã«èªè¨¼æ©è½ãæä¾ããgemã ããDeviseã使ãã¨ã¦ã¼ã¶ã¼ã¯ãµã¤ã³ã¢ããããã°ã¤ã³ãã§ããããã«ãªããã
001 Deviseã使ã£ã¦ã¿ãã
ð± Deviseãã©ããªæããªã®ãå®éã«ä½¿ã£ã¦ã¿ããï¼
ð± ã¾ãã¯Deviseãinstallãããã
# Gemfile gem "devise"
$ bundle install
ð± 次ã¯$ rails g devise:install
ã³ãã³ããå®è¡ãã¦ããDeviseã®è¨å®ãã¡ã¤ã«ï¼devise.rb
ï¼ã¨ãã±ã¼ã«ãã¡ã¤ã«ï¼devise.en.yml
ï¼ãä½æããã¦ãè±èªã§ã»ããã¢ããã®æ示ã表示ããããã
$ rails g devise:install create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Depending on your application's configuration some manual setup may be required: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. * Required for all applications. * 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" * Not required for API-only Applications * 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> * Not required for API-only Applications * 4. You can copy Devise views (for customization) to your app by running: rails g devise:views * Not required * ===============================================================================
ð± æ示éãã«ã»ããã¢ãããé²ãã¦ããããã¾ãã¯ActionMailerã«ããã©ã«ãURLãè¨å®ããããDeviseã¯ãã¹ã¯ã¼ããªã»ãããªã©ã§ã¦ã¼ã¶ã¼ã«ã¡ã¼ã«ãéä¿¡ããã®ã ãã©ããããè¨å®ãã¦ãããã¨ã§ã¡ã¼ã«å ã®ãªã³ã¯ãæ£ãã表示ã§ããããã«ãªãããéçºç°å¢ã¨æ¬çªç°å¢ã®è¨å®ãã¡ã¤ã«ã«ããããè¨å®ãã¦ãã
# config/environments/development.rb # éçºç°å¢ã¯ãã®ã¾ã¾ã³ããã§ããã config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
# config/environments/production.rb # æ¬çªç°å¢ã§ã¯hoståãæå®ãã¦ã config.action_mailer.default_url_options = { host: 'xxxx.com' }
ð± 次ã¯rootã®ã«ã¼ãã£ã³ã°ãè¨å®ããããããã§ã¯HomeController
ã®index
ã¢ã¯ã·ã§ã³ãè¨å®ãããã
# config/routes.rb root to: "home#index"
ð± HomeController
ãä½æãã¦ãããã
$ rails g controller home index
ð± flashã¡ãã»ã¼ã¸ã表示ã§ããããã«ãããããããè¨å®ãã¦ããã¨ãã¦ã¼ã¶ã¼ããã°ã¤ã³ããæãªã©ã«ããã°ã¤ã³ãã¾ããããã®ãããªã¡ãã»ã¼ã¸ãç»é¢ã«è¡¨ç¤ºã§ããããã«ãªãããã¬ã¤ã¢ã¦ãã¢ã¦ããã³ãã¬ã¼ãã«notice
ã¨alert
ã表示ããã³ã¼ãã追å ãã¦ãã
# app/views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title>DemoApp</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <!-- ãã®2è¡ã追å ãã¦ã --> <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> <%= yield %> </body> </html>
ð± 次ã¯Deviseã®ãã¥ã¼ãã¡ã¤ã«ãèªåã®ããã¸ã§ã¯ãã«ã³ãã¼ãããããã®ã¾ã¾ã§ãDeviseã¯åããã©ãã³ãã¼ãã¦ãããã¨ã§ãã¥ã¼ãã¡ã¤ã«ãèªç±ã«ã«ã¹ã¿ãã¤ãºã§ããããã«ãªããã
$ rails g devise:views invoke Devise::Generators::SharedViewsGenerator create app/views/devise/shared create app/views/devise/shared/_error_messages.html.erb create app/views/devise/shared/_links.html.erb invoke form_for create app/views/devise/confirmations create app/views/devise/confirmations/new.html.erb create app/views/devise/passwords create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb create app/views/devise/registrations create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb create app/views/devise/sessions create app/views/devise/sessions/new.html.erb create app/views/devise/unlocks create app/views/devise/unlocks/new.html.erb invoke erb create app/views/devise/mailer create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/email_changed.html.erb create app/views/devise/mailer/password_change.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erb
ð± Userã¢ãã«ãä½æãããã$ rails g devise User
ãå®è¡ããã¨ãUserã¢ãã«ã¨usersãã¼ãã«ãä½æããããã®migrationãã¡ã¤ã«ãä½æããããã
$ rails g devise User invoke active_record create db/migrate/20201103065100_devise_create_users.rb create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml insert app/models/user.rb route devise_for :users
ð± db:migrateãå®è¡ãã¦usersãã¼ãã«ãä½æãã¦ãã
$ rails db:migrate
ð± ããã§å®äºã ãããµã¼ãã¼ãèµ·åãã¦ããã©ã¦ã¶ãã http://localhost:3000/users/sign_in
ã«ã¢ã¯ã»ã¹ããã¨ãã°ã¤ã³ç»é¢ã表示ããããã
$ rails server
ð± ãã°ã¤ã³ã ãã§ãªãããµã¤ã³ã¢ãããªã©ã®æ©è½ã使ããã®ã§éãã§ã¿ã¦ãã
002 ãã«ãã¼ã使ã£ã¦ã¿ãã
ð± Deviseã¯ã³ã³ããã¼ã©ã¼ã¨ãã¥ã¼ã§ä½¿ãããã«ãã¼ã¡ã½ãããæä¾ãã¦ããããã
ð± HomeController
ã«ä»¥ä¸ã®ã³ã¼ãã追å ãã¦ãã
# app/controllers/home_controller.rb class HomeController < ApplicationController # ãªã¯ã¨ã¹ããã¦ããã¦ã¼ã¶ã¼ãèªè¨¼ããã # ã¦ã¼ã¶ã¼ããã°ã¤ã³æ¸ã¿ã®å ´åã¯ã¢ã¯ã»ã¹ã許å¯ãã¦ãæªãã°ã¤ã³ã®å ´åã¯root_pathã«ãªãã¤ã¬ã¯ãããã before_action :authenticate_user! def index end end
ð± before_action :authenticate_user!
ãå©ç¨ãããã¨ã§ãHomeController
ã¸ã®ã¢ã¯ã»ã¹ãèªè¨¼ã§ããããã«ãªãããããã¦ã¼ã¶ã¼ãæªãã°ã¤ã³ã ã£ãããã®ã³ã³ããã¼ã©ã¼ã«ã¯ã¢ã¯ã»ã¹ã§ããã«ãroot_pathã¸ãªãã¤ã¬ã¯ãããããã¨ã«ãªããã
ð± æå®ã®ã¢ã¯ã·ã§ã³ã ãèªè¨¼ãããå ´åã¯only
ãªãã·ã§ã³ã使ãã°OKã ãã
# app/controllers/home_controller.rb class HomeController < ApplicationController before_filter :authenticate_user!, only: %i(index) def index end def new end end
ð± ããã§newã¢ã¯ã·ã§ã³ã¯èªè¨¼ããªãã®ã§ãæªãã°ã¤ã³ç¶æ ã§ãã¢ã¯ã»ã¹ã§ãããã
ð± ä»ã«ãuser_signed_in?
ãcurrent_user
ãªã©ã®ã¡ã½ããã追å ããããã
# app/controllers/home_controller.rb class HomeController < ApplicationController def index # user_signed_in?: ãã°ã¤ã³æ¸ã¿ã®å ´åã¯trueãè¿ãã # current_user: ãã°ã¤ã³æ¸ã¿ã®å ´åã¯ãã°ã¤ã³ã¦ã¼ã¶ã¼ãè¿ãã # ãã°ã¤ã³æ¸ã¿ã®å ´åããã°ã¤ã³ã¦ã¼ã¶ã¼ã®idããã°ã«æ¸ãè¾¼ãã if user_signed_in? logger.debug current_user.id end # ...çç¥... end end
ð± ãããã®ãã«ãã¼ã使ã£ã¦ã¢ããªã±ã¼ã·ã§ã³ãéçºãã¦ãããã¨ã«ãªãããä»ã®ãã«ãã¼ã«ã¤ãã¦ã¯ ã³ã³ããã¼ã©ã¼ã»ãã¥ã¼ã®ã¡ã½ãã ãåç §ãã¦ãã
第2ç« ã¢ã¸ã¥ã¼ã«ã使ã
003 ã¢ã¸ã¥ã¼ã«ã¨ã¯ï¼
ð± èªè¨¼ã§ã¯ããã°ã¤ã³ã以å¤ã«ããããµã¤ã³ã¢ããããããã¹ã¯ã¼ããªã»ããããªã©ãããããªæ©è½ãå¿ è¦ã«ãªããããDeviseã¯èªè¨¼ã®åæ©è½ãã¢ã¸ã¥ã¼ã«ã¨ãã¦æä¾ãã¦ããããä¾ãã°ããã°ã¤ã³æã«ä½åº¦ããã¹ã¯ã¼ããééããå ´åã¯ãã¢ã«ã¦ã³ããããã¯ãããããã¿ãããªå ´åãããããããªæã¯Lockableã¢ã¸ã¥ã¼ã«ãæå¹ã«ãã¦ãããã°ãèªåã§ã³ã¼ããæ¸ããªãã¦ãDeviseãã¢ã«ã¦ã³ãããã¯ã®æ©è½ã追å ãã¦ããããã ãã¢ããªã±ã¼ã·ã§ã³ã«ãã£ã¦è¦ä»¶ã¯å¤ããããã©ããDeviseã¯åæ©è½ãã¢ã¸ã¥ã¼ã«å½¢å¼ã«ãªã£ã¦ããã®ã§ãå¿ è¦ãªã¢ã¸ã¥ã¼ã«ã ããé¸ãã§ä½¿ããã¨ãã§ãããã
ã¢ã¸ã¥ã¼ã«ã®ç¨®é¡
ð± ã¢ã¸ã¥ã¼ã«ã¯å ¨é¨ã§10åãããã
ã¢ã¸ã¥ã¼ã«å | æ©è½ | ããã©ã«ã |
---|---|---|
Registerable | ãµã¤ã³ã¢ããæ©è½ | æå¹ |
Database Authenticatable | Email/Passwordå ¥åã«ãããã°ã¤ã³æ©è½ | æå¹ |
Rememberable | Remember Meæ©è½ï¼ãã©ã¦ã¶ãéãã¦ããã°ã¤ã³ãç¶ç¶ããæ©è½ï¼ | æå¹ |
Recoverable | ãã¹ã¯ã¼ããªã»ããæ©è½ | æå¹ |
Validatable | Email/Passwordã®ããªãã¼ã·ã§ã³æ©è½ | æå¹ |
Confirmable | ãµã¤ã³ã¢ããæã«æ¬ç»é²ç¨ã®ã¡ã¼ã«ãéä¿¡ãã¦ãã¡ã¼ã«ã¢ãã¬ã¹ã確èªããæ©è½ | ç¡å¹ |
Trackable | ãã°ã¤ã³æã®æ å ±ï¼IPã¢ãã¬ã¹ãªã©ï¼ãDBã«ä¿åããæ©è½ | ç¡å¹ |
Timeoutable | ä¸å®æéã¢ã¯ã»ã¹ããªãã¨å¼·å¶ãã°ã¢ã¦ããããæ©è½ | ç¡å¹ |
Lockable | æå®åæ°ãã°ã¤ã³å¤±æã§ã¢ã«ã¦ã³ããããã¯ããæ©è½ | ç¡å¹ |
Omniauthable | Omniauthã¨ã®é£æºæ©è½ï¼Twitterã»Googleã¢ã«ã¦ã³ããªã©ã§ãã°ã¤ã³ã§ããï¼ | ç¡å¹ |
ð± ã¢ã¸ã¥ã¼ã«ã¯Userã¢ãã«ã®devise
ã¡ã½ããã§æå®ããã¨æå¹ã«ã§ãããã ãããã©ã«ãã§ã¯database_authenticatable
ãregisterable
ãrecoverable
ãrememberable
ãvalidatable
ã®5ã¤ã®ã¢ã¸ã¥ã¼ã«ãæå¹ã«ãªã£ã¦ãããã
# app/models/user.rb class User < ApplicationRecord # 以ä¸ã®5ã¤ã®ã¢ã¸ã¥ã¼ã«ã¯ããã©ã«ãã§ã¯ç¡å¹ã ãã # :confirmable, :lockable, :timeoutable, :trackable, :omniauthable # 以ä¸ã®5ã¤ã®ã¢ã¸ã¥ã¼ã«ãããã©ã«ãã§æå¹ã ãã devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable end
ð± ããã©ã«ãã§æå¹ã«ãªã£ã¦ãã5ã¤ã®ã¢ã¸ã¥ã¼ã«ã¯ãç¹å¥ãªäºæ ããªãéããã®ã¾ã¾æå¹ã«ãã¦ããã°ããã¨æãããããã©ã«ãã§ç¡å¹ã«ãªã£ã¦ãã5ã¤ã®ã¢ã¸ã¥ã¼ã«ã¯å¿ è¦ã«å¿ãã¦æå¹ã«ãã¦ãã
ã¢ã¸ã¥ã¼ã«ã®ã«ã©ã
ð± ã¢ã¸ã¥ã¼ã«ã«ãã£ã¦ã¯usersãã¼ãã«ã«ã«ã©ã ã追å ããå¿ è¦ããããã
ð± rails g devise:install
ã³ãã³ãã§ä½æããããã¤ã°ã¬ã¼ã·ã§ã³ãã¡ã¤ã«ãè¦ã¦ã¿ããã
# db/migrate/20201103065100_devise_create_users.rb # frozen_string_literal: true class DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable # t.integer :sign_in_count, default: 0, null: false # t.datetime :current_sign_in_at # t.datetime :last_sign_in_at # t.string :current_sign_in_ip # t.string :last_sign_in_ip ## Confirmable # t.string :confirmation_token # t.datetime :confirmed_at # t.datetime :confirmation_sent_at # t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end
ð± ãããªæãã§ã¢ã¸ã¥ã¼ã«æ¯ã«å¿
è¦ãªã«ã©ã ãç¨æããã¦ããããä¾ãã°Confirmableã¢ã¸ã¥ã¼ã«ãæå¹ã«ãããå ´åã¯ãã³ã¡ã³ãã¢ã¦ãããã¦ããconfirmation_token
ãªã©ãã¢ã³ã³ã¡ã³ãããå¿
è¦ããããã
# db/migrate/20201103065100_devise_create_users.rb # frozen_string_literal: true class DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable # t.integer :sign_in_count, default: 0, null: false # t.datetime :current_sign_in_at # t.datetime :last_sign_in_at # t.string :current_sign_in_ip # t.string :last_sign_in_ip ## Confirmable # ãããã®ã«ã©ã ãå¿ è¦ã«ãªãã®ã§ã¢ã³ã³ã¡ã³ããã¦ãã t.string :confirmation_token t.datetime :confirmed_at t.datetime :confirmation_sent_at t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # ã«ã©ã ã«å¯¾å¿ããã¤ã³ããã¯ã¹ãã¢ã³ã³ã¡ã³ããã¦ãã add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end
ð± ããã§ãã¤ã°ã¬ã¼ã·ã§ã³ãå®è¡ããã°ã¢ã¸ã¥ã¼ã«ã«å¿ è¦ãªã«ã©ã ã追å ã§ãããã
$ rails db:migrate
ð± å¾ããã¢ã¸ã¥ã¼ã«ã追å ããå ´åã¯ãã«ã©ã ã追å ãããã¤ã°ã¬ã¼ã·ã§ã³ãã¡ã¤ã«ãä½æããã°OKã ãã
$ rails g migration add_confirmable_columns_to_users invoke active_record create db/migrate/20201115225427_add_confirmable_columns_to_users.rb
# db/migrate/20201115225427_add_confirmable_columns_to_users.rb class AddConfirmableColumnsToUsers < ActiveRecord::Migration[6.0] def change change_table :users do |t| # Confirmableã«å¿ è¦ãªã«ã©ã t.string :confirmation_token t.datetime :confirmed_at t.datetime :confirmation_sent_at t.string :unconfirmed_email end add_index :users, :confirmation_token, unique: true end end
ã¢ã¸ã¥ã¼ã«ã®ã«ã¼ãã£ã³ã°
ð± Deviseã®ã«ã¼ãã£ã³ã°ã¯devise_for
ã¡ã½ãããç¨æãã¦ããããã
# config/routes.rb Rails.application.routes.draw do devise_for :users end
ð± ã¢ã¸ã¥ã¼ã«ãæå¹ã«ããã¨ãdevise_for
ã¡ã½ããã«ãã£ã¦ã¢ã¸ã¥ã¼ã«ã«å¯¾å¿ããã«ã¼ãã£ã³ã°ãèªåçã«è¿½å ãããããããã©ã«ãã§ã¯5ã¤ã®ã¢ã¸ã¥ã¼ã«ãæå¹ã«ãªã£ã¦ããã®ã§ãããã«å¯¾å¿ããã«ã¼ãã£ã³ã°ã追å ããã¦ãããããã ãå
¨ã¦ã®ã¢ã¸ã¥ã¼ã«ã«ã³ã³ããã¼ã©ã¼ãããããã§ã¯ãªããä»åã§ããã°database_authenticatable
ãregisterable
ãrecoverable
ã®3ã¤ã®ã¢ã¸ã¥ã¼ã«ã«ã³ã³ããã¼ã©ã¼ãåå¨ãããã ããã®ãããã®3ã¤ã®ã³ã³ããã¼ã©ã¼ã«å¯¾å¿ããã«ã¼ãã£ã³ã°ã追å ããããã
$ rails routes Prefix Verb URI Pattern Controller#Action new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy new_user_password GET /users/password/new(.:format) devise/passwords#new edit_user_password GET /users/password/edit(.:format) devise/passwords#edit user_password PATCH /users/password(.:format) devise/passwords#update PUT /users/password(.:format) devise/passwords#update POST /users/password(.:format) devise/passwords#create cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel new_user_registration GET /users/sign_up(.:format) devise/registrations#new edit_user_registration GET /users/edit(.:format) devise/registrations#edit user_registration PATCH /users(.:format) devise/registrations#update PUT /users(.:format) devise/registrations#update DELETE /users(.:format) devise/registrations#destroy POST /users(.:format) devise/registrations#create
ð± Confirmableã¢ã¸ã¥ã¼ã«ãæå¹ã«ããã¨ãConfirmableã¢ã¸ã¥ã¼ã«ç¨ã®ã«ã¼ãã£ã³ã°ã追å ããããã
# app/models/user.rb class User < ApplicationRecord # Confirmableã¢ã¸ã¥ã¼ã«ã追å ãã devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :confirmable end
$ rails routes Prefix Verb URI Pattern Controller#Action new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy new_user_password GET /users/password/new(.:format) devise/passwords#new edit_user_password GET /users/password/edit(.:format) devise/passwords#edit user_password PATCH /users/password(.:format) devise/passwords#update PUT /users/password(.:format) devise/passwords#update POST /users/password(.:format) devise/passwords#create cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel new_user_registration GET /users/sign_up(.:format) devise/registrations#new edit_user_registration GET /users/edit(.:format) devise/registrations#edit user_registration PATCH /users(.:format) devise/registrations#update PUT /users(.:format) devise/registrations#update DELETE /users(.:format) devise/registrations#destroy POST /users(.:format) devise/registrations#create # Confirmableã¢ã¸ã¥ã¼ã«ç¨ã®ã«ã¼ãã£ã³ã°ã追å ããã new_user_confirmation GET /users/confirmation/new(.:format) devise/confirmations#new user_confirmation GET /users/confirmation(.:format) devise/confirmations#show POST /users/confirmation(.:format) devise/confirmations#create
ð± ã«ã¼ãã£ã³ã°ã¯æå¹ãªã¢ã¸ã¥ã¼ã«ã«ãã£ã¦èªåã§æ±ºã¾ãã®ã§ãroutes.rb
ã®ç·¨éã¯ä¸è¦ã ãã
ã¢ã¸ã¥ã¼ã«ã®ã³ã³ããã¼ã©ã¼ã¨ãã¥ã¼
ð± ã¢ã¸ã¥ã¼ã«ã«ãã£ã¦ã¯ã³ã³ããã¼ã©ã¼ã¨ãã¥ã¼ãæä¾ãããã®ãããããä¾ãã°Confirmableã¢ã¸ã¥ã¼ã«ã¯Devise::ConfirmationsController
ã¨ããã«å¯¾å¿ãããã¥ã¼ãæä¾ãããã
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/confirmation | devise/confirmations#show | confirmãã¡ã¼ã«ã®ãªã³ã¯å ã¯ãããã¯ã¨ãªãã©ã¡ã¼ã¿ã¼ã®confirmation_tokenãä¸è´ããªãã¨ã¢ã¯ã»ã¹ã§ããªãã |
GET | /users/confirmation/new | devise/confirmations#new | confirmæ示ã¡ã¼ã«åéä¿¡ç»é¢ã |
POST | /users/confirmation | devise/confirmations#create | confirmæ示ã¡ã¼ã«éä¿¡ã |
ã¢ã¸ã¥ã¼ã«ã®ã¡ã½ãã
ð± ã¢ã¸ã¥ã¼ã«ã追å ããã¨User
ã«ã¡ã½ããã追å ãããããä¾ãã°Confirmableã¢ã¸ã¥ã¼ã«ã追å ããã¨ã確èªã¡ã¼ã«ãéä¿¡ããããã®User#send_confirmation_instructions
ã¡ã½ãããªã©ã追å ãããããé常ã§ããã°ã¦ã¼ã¶ã¼ã«å¯¾ããæä½ã¯ç¨æãããDeviseã®ã³ã³ããã¼ã©ã¼ããè¡ãã®ã§ããããã®ã¡ã½ãããç´æ¥ä½¿ããã¨ã¯å°ãªããããã æåã§æä½ãããå ´åã«ã¯ãç´æ¥ãããã®ã¡ã½ããã使ããã¨ã«ãªããã
# æåã§Confirmã¡ã¼ã«ãéä¿¡ user.send_confirmation_instructions # confirmãã # å ·ä½çã«ã¯confirmed_atã«ç¾å¨æå»ãè¨å®ãã user.confirm # confirmæ¸ã¿ãªããtrue user.confirmed?
ã¢ã¸ã¥ã¼ã«ã®ã¡ã¼ã«éä¿¡
ð± ã¡ã¼ã«ãéä¿¡ããããã«ActionMailerãå©ç¨ããã¢ã¸ã¥ã¼ã«ãããããä¾ãã°Confirmableã¢ã¸ã¥ã¼ã«ã§ããã°ç¢ºèªã¡ã¼ã«ã§ããDevise::Mailer#confirmation_instructions
ãæä¾ãããã
ã¢ã¸ã¥ã¼ã«ã®è¨å®
ð± åã¢ã¸ã¥ã¼ã«ã¯å°ç¨ã®è¨å®ããããè¨å®ãå¤æ´ãããã¨ã§ã¢ã¸ã¥ã¼ã«ã®æåãå¤æ´ã§ãããã
# config/initializers/devise.rb # Confirmableã¢ã¸ã¥ã¼ã«ã®è¨å® # 確èªã¡ã¼ã«ã®æå¹æé config.confirm_within = 3.days
004 Registerableã¢ã¸ã¥ã¼ã«
ð± ããããã¯åã¢ã¸ã¥ã¼ã«ã®è§£èª¬ããã¦ãããã
ð± Registerableã¢ã¸ã¥ã¼ã«ã¯ãµã¤ã³ã¢ããæ©è½ãæä¾ããããå ·ä½çã«ã¯Userã¬ã³ã¼ããä½æ/æ´æ°/åé¤ããæ©è½ãæä¾ãããã
ã³ã³ããã¼ã©ã¼ã¨ã«ã¼ãã£ã³ã°
ð± Registerableã¢ã¸ã¥ã¼ã«ã§ã¯Devise::RegistrationsController
ã¨ããã³ã³ããã¼ã©ã¼ã¨ä»¥ä¸ã®6ã¤ã®ã¢ã¯ã·ã§ã³ãç¨æããããã
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/sign_up | devise/registrations#new | ãµã¤ã³ã¢ããç»é¢ |
GET | /users/edit | devise/registrations#edit | ã¢ã«ã¦ã³ãç·¨éç»é¢ãemailãpasswordãç·¨éã§ããã |
POST | /users | devise/registrations#create | ã¢ã«ã¦ã³ãç»é² |
PATCH/PUT | /users | devise/registrations#update | ã¢ã«ã¦ã³ãæ´æ° |
DELETE | /users | devise/registrations#destroy | ã¢ã«ã¦ã³ãåé¤ |
GET | /users/cancel | devise/registrations#cancel | sessionåé¤ãOAuthã®sessionãã¼ã¿ãåé¤ãããå ´åã«ä½¿ãã |
ð± /users/sign_up
ãéãã¨ãµã¤ã³ã¢ããç»é¢ã表示ããããã
ð± Registrationï¼ç»é²ï¼ã¨ãããªã½ã¼ã¹ãnewï¼æ°è¦ä½æï¼ããããDevise::RegistrationsController#new
ã«ãªã£ã¦ããããpathã¯Restfulã«èããã¨/registration/new
ã«ãªãã®ã ãã©ããµã¤ã³ã¢ããç»é¢ã§ãããã¨ããããããããªãããã«/users/sign_up
ã¨ãªã£ã¦ãããã
ð± ãµã¤ã³ã¢ããããã¨Userã¬ã³ã¼ããä½æããã¦ããµã¤ã³ã¤ã³ç¶æ
ã«ãªããã¢ã«ã¦ã³ãç·¨éç»é¢ï¼/users/edit
ï¼ã«ãªãã¤ã¬ã¯ããããããã¢ã«ã¦ã³ãç·¨éç»é¢ã§ã¯ã¦ã¼ã¶ã¼ãèªåã®ã¢ã«ã¦ã³ãæ
å ±ã§ããemailãpasswordãç·¨éã§ãããã
è¨å®
ð± Registerableã¢ã¸ã¥ã¼ã«ã§è¨å®ã§ããé ç®ã¯ä»¥ä¸ã®éãã ãã
# config/initializers/devise.rb # ãã¹ã¯ã¼ãå¤æ´å¾ã«èªåçã«ãµã¤ã³ã¤ã³ãããã config.sign_in_after_change_password = true
åè
005 Database Authenticatableã¢ã¸ã¥ã¼ã«
ð± Database Authenticatableã¢ã¸ã¥ã¼ã«ã使ãã¨ãemailã¨passwordã§ãã°ã¤ã³ã§ããããã«ãªããã
ð¦ð» emailã¨password以å¤ã®ãã°ã¤ã³æ¹æ³ãããã£ã¦ãã¨ï¼
ð± ããã ããå¾ã§ã§ã¦ãããã©ãä¾ãã°Omniauthableã¢ã¸ã¥ã¼ã«ã使ãã°ãTwitterãGoogleã®ã¢ã«ã¦ã³ãã使ã£ã¦ãã°ã¤ã³ã§ããããã«ãªãããããã§ã¯Database Authenticatableã¢ã¸ã¥ã¼ã«ã使ã£ãemailã¨passwordã§ã®ãã°ã¤ã³ã«ã¤ãã¦è§£èª¬ãããã
ã³ã³ããã¼ã©ã¼ã¨ã«ã¼ãã£ã³ã°
ð± Database Authenticatableã¢ã¸ã¥ã¼ã«ã§ã¯Devise::SessionsController
ã¨ããã³ã³ããã¼ã©ã¼ã¨ä»¥ä¸ã®3ã¤ã®ã¢ã¯ã·ã§ã³ãç¨æããããã
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/sign_in | devise/sessions#new | ãã°ã¤ã³ç»é¢ |
POST | /users/sign_in | devise/sessions#create | ãã°ã¤ã³ |
DELETE | /users/sign_out | devise/sessions#destroy | ãã°ã¢ã¦ã |
ð± ãã©ã¦ã¶ãã localhost:3000/users/sign_in
ãéãã¨ãã°ã¤ã³ç»é¢ã表示ããããã
ð± Deviseã§ã¯ãã°ã¤ã³æã«Sessionãä½æããããSession
ããªã½ã¼ã¹ã ã¨èãã¦ããããnew
ï¼æ°è¦ä½æï¼ããããããã°ã¤ã³ç»é¢ã®ã¢ã¯ã·ã§ã³ã¯Devise::SessionsController#new
ã¨ãªã£ã¦ããããpathã¯ãã°ã¤ã³ç»é¢ã ã¨ãããã¨ãããããããããã«ã/session/new
ã§ã¯ãªã/users/sign_in
ã¨ãªã£ã¦ãããã
ð± ãã°ã¤ã³å¾ã«Devise::SessionsController#destroy
ãå©ãã°ãã°ã¢ã¦ãã§ãããããããªæãã®ãªã³ã¯ãç¨æãã¦ãã
<!-- destroy_user_session_pathã¯`/users/sign_out`ãæãURLãã«ãã¼ã ã --> <!-- HTTPã¡ã½ããã«ã¯DELETEã¡ã½ãããæå®ãã¦ã --> <%= link_to "ãã°ã¢ã¦ã", destroy_user_session_path, method: :delete %>
ã«ã©ã
ð± Database Authenticatableã¢ã¸ã¥ã¼ã«ã§ã¯ãusersãã¼ãã«ã«ä»¥ä¸ã®2ã¤ã®ã«ã©ã ãå¿ è¦ã«ãªããã
ã«ã©ã | æ¦è¦ |
---|---|
ã¡ã¼ã«ã¢ãã¬ã¹ã èªè¨¼ã«å©ç¨ã DBçã«ã¯ã¦ãã¼ã¯ãã¼ã«ãªããã¦ã¼ã¶ã¼ã¯éè¤ããã¡ã¼ã«ã¢ãã¬ã¹ãç»é²ãããã¨ãã§ããªããã |
|
encrypted_password | ããã·ã¥åããããã¹ã¯ã¼ãã èªè¨¼ã«å©ç¨ã ãã¹ã¯ã¼ããç´æ¥DBã«ä¿åããã®ã¯ã»ãã¥ãªãã£ã¼çã«åé¡ãããã®ã§ãããã·ã¥åãããã¹ã¯ã¼ããDBã«ä¿åããããDeviseã§ã¯å é¨çã«bcryptã¨ããããã·ã¥åé¢æ°ã使ã£ã¦ãã¦ãDBä¿ååã«èªåçã«ããã·ã¥åãã¦ããããã |
è¨å®
ð± Database Authenticatableã¢ã¸ã¥ã¼ã«ã§è¨å®ã§ããé ç®ã¯ä»¥ä¸ã®éãã ãã
# config/initializers/devise.rb # ããã·ã¥åã®ã¬ãã«ã # ããã·ã¥åã«ã¯çµæ§æéããããã # bcryptï¼ããã©ã«ãã®ã¢ã«ã´ãªãºã ï¼ã®å ´åã¬ãã«ã«å¿ãã¦ææ°é¢æ°çã«é ããªããä¾ãã°ã¬ãã«20ã§ã¯60ç§ç¨åº¦ãããã # ãã¹ãã®æã¯ã¬ãã«1ã«ãã¦é度ãä¸ããã # æ¬çªã§ã¯ã¬ãã«10以ä¸ã¯å©ç¨ãã¹ãã§ãªãã config.stretches = Rails.env.test? ? 1 : 11 # ããã·ã¥åããéã®ãããã¼ãï¼saltã¿ãããªãã¤ãï¼ # 詳細㯠https://stackoverflow.com/questions/6831796/whats-the-most-secure-possible-devise-configuration config.pepper = 'e343ec013eac51040db52ee0cc22175d262f8bd87badc7ec87dcba597ccde6e4449b7890bba62d8598fd8f33b0ffbb7ad128ee5e39a18509691851cbfc81b80a' # emailå¤æ´æã«emailå¤æ´å®äºã¡ã¼ã«ãéä¿¡ããã config.send_email_changed_notification = false # passwordå¤æ´æã«passwordå¤æ´å®äºã¡ã¼ã«ãéä¿¡ããã config.send_password_change_notification = false
ã¡ã½ãã
ð± Database Authenticatableã¢ã¸ã¥ã¼ã«ã§ã¯Userã¢ãã«ã«ä»¥ä¸ã®ã¡ã½ãããæä¾ãããã
# passwordãã»ããããã # å é¨ã§æå·åãã¦`encrypted_password`ã«ã»ãããã¦ããããã user.password = "password" user.encrypted_password #=> "$2a$12$V/xUMhmLEZApbyv2Y0jI4eyJ0gYE8JlVPL2/1Yr9jcFXChnQzC0Hi" # ãã¹ã¯ã¼ããæ£ãããã°trueã # å¼æ°ã®ãã¹ã¯ã¼ããããã·ã¥åãã¦encrypted_passwordã®å¤ã¨æ¯è¼ãã¦ãããã user.valid_password?('password') #=> true # passwordã¨password_confirmationã«nilãã»ããã user.clean_up_passwords user.password #=> nil user.password_confirmation #=> nil
ã¡ã¼ã«
ð± Database Authenticatableã¢ã¸ã¥ã¼ã«ã§ã¯ä»¥ä¸ã®2ã¤ã®ã¡ã¼ã«ãéä¿¡ãããã
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#email_changed | Eã¡ã¼ã«å¤æ´å®äºã¡ã¼ã«ãEã¡ã¼ã«å¤æ´æã«éä¿¡ããã |
Devise::Mailer#password_change | ãã¹ã¯ã¼ãå¤æ´å®äºã¡ã¼ã«ããã¹ã¯ã¼ãå¤æ´æã«éä¿¡ããã |
ð± ãã®2ã¤ã¯ããã©ã«ãã§ã¯ã¡ã¼ã«éä¿¡ããªãè¨å®ã«ãªã£ã¦ããã®ã§ãããã¡ã¼ã«éä¿¡ãããå ´åã¯è¨å®ãå¤æ´ãã¦ãã
# config/initializers/devise.rb # emailå¤æ´æã«emailå¤æ´å®äºã¡ã¼ã«ãéä¿¡ããã config.send_email_changed_notification = true # passwordå¤æ´æã«passwordå¤æ´å®äºã¡ã¼ã«ãéä¿¡ããã config.send_password_change_notification = true
åè
006 Rememberableã¢ã¸ã¥ã¼ã«
ð± Rememberableã¢ã¸ã¥ã¼ã«ã¯Remember Meæ©è½ãæä¾ããããCookieã«ã¦ã¼ã¶ã¼ã®ãã¼ã¯ã³ãä¿åãããã¨ã§ãã»ãã·ã§ã³ãåãã¦ãCookieããã¦ã¼ã¶ã¼ãåå¾ãã¦ããã°ã¤ã³ç¶æ ãç¶æã§ãããã
ð± Rememberableã¢ã¸ã¥ã¼ã«ãæå¹ã ã¨ããã°ã¤ã³ç»é¢ã«Remember meã¨ãããã§ãã¯ããã¯ã¹ãç¨æãããããã¦ã¼ã¶ã¼ã¯ããã«ãã§ãã¯ãå ¥ãã¦ãã°ã¤ã³ãããã¨ã§ãRemember Meãå©ç¨ã§ãããã ã
ã«ã©ã
ã«ã©ã | æ¦è¦ |
---|---|
remember_created_at | Remenber Meããæå» |
remember_token | remember_meç¨ã®token remember_tokenã«ã©ã ããªããã°ãencrypted_passwordã®å é 30æåã§ä»£ç¨ããã®ã§ãå¥ã«ãªãã¦ãOKã ãããã¤ã°ã¬ã¼ã·ã§ã³ãã¡ã¤ã«ã«ãè¨è¼ãããªããã |
è¨å®
# config/initializers/devise.rb # Sessionãåããã¾ã§ã®æéã # ããã©ã«ãã¯2.weeksã config.remember_for = 2.weeks # ãã°ã¢ã¦ãæã«remember_tokenãæéåãã«ããã config.expire_all_remember_me_on_sign_out = true # cookieå©ç¨æã«æéã伸ã°ãã config.extend_remember_period = false # cookieã«ã»ãããããªãã·ã§ã³ã config.rememberable_options = {secure: true}
ã¡ã½ãã
# remember_tokenãä½æ user.remember_me! # remember_tokenãåé¤ user.forget_me! # useræ å ±ã使ã£ã¦cookieãä½æ User.serialize_into_cookie(user) # cookieæ å ±ã使ã£ã¦userãåå¾ User.serialize_from_cookie(cookie_string)
åè
- devise/rememberable.rb at master · heartcombo/devise · GitHub
- Devise3.2.2 ã®ããã©ã«ãè¨å®ã§ã¯ãRememberable ã® remember_token ã®ã«ã©ã ããªãã®ã§ã½ã¼ã¹ã解èªãã¦ã¿ã | EasyRamble
007 Recoverableã¢ã¸ã¥ã¼ã«
ð± Recoverableã¢ã¸ã¥ã¼ã«ã¯ãã¹ã¯ã¼ããªã»ããæ©è½ãæä¾ãããããã¹ã¯ã¼ããå¿ãã¦ãã°ã¤ã³ã§ããªãã¦ã¼ã¶ã¼ã®ããã«ããã¹ã¯ã¼ããåè¨å®ã§ãããªã³ã¯ãã¡ã¼ã«ã§éä¿¡ã§ããããRecoverableã¢ã¸ã¥ã¼ã«ã¯ãã°ã¤ã³åã«ãã¹ã¯ã¼ããå¤æ´ããæ©è½ãªã®ã§ããã°ã¤ã³å¾ã«ãã¹ã¯ã¼ããå¤æ´ãããå ´åã¯Registerableã¢ã¸ã¥ã¼ã«ã®ã¢ã«ã¦ã³ãç·¨éæ©è½ï¼/users/edit
ï¼ã使ã£ã¦ãã
ð± å®éã«ã©ããªæ©è½ã使ã£ã¦ã¿ããããã°ã¤ã³ç»é¢ã«è¡ãã¨ä¸çªä¸ã«ãForgot your password?ãã¨ãããªã³ã¯ããããããããã¯ãªãã¯ãã¦ãã
ð± ãã¹ã¯ã¼ããªã»ããã®ã¡ã¼ã«éä¿¡ç»é¢ï¼/users/password/new
ï¼ã«é·ç§»ããããããã§ãã¹ã¯ã¼ããªã»ãããããã¢ã«ã¦ã³ãã®ã¡ã¼ã«ã¢ãã¬ã¹ãå
¥åãã¦submitãã¦ãã
ð± ããã¨å ¥åããã¡ã¼ã«ã¢ãã¬ã¹å®ã«ããããªã¡ã¼ã«ãéä¿¡ããããã
ð± ã¡ã¼ã«å
ã®ãChange my passwordãã¨ãããªã³ã¯ãã¯ãªãã¯ãã¦ãããã¹ã¯ã¼ãåè¨å®ç»é¢ï¼/users/password/edit
ï¼ã«é·ç§»ãããã
ð± ãã¹ã¯ã¼ãã¨ç¢ºèªç¨ãã¹ã¯ã¼ããå ¥åãã¦submitããã¨ããã¹ã¯ã¼ããåè¨å®ããã¦ããã°ã¤ã³ç¶æ ã«ãªããã
ã³ã³ããã¼ã©ã¼ã¨ã«ã¼ãã£ã³ã°
ð± Recoverableã¢ã¸ã¥ã¼ã«ã§ã¯Devise::PasswordsController
ã¨ããã³ã³ããã¼ã©ã¼ã¨ä»¥ä¸ã®4ã¤ã®ã¢ã¯ã·ã§ã³ãç¨æããããã
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/password/new | devise/passwords#new | ãã¹ã¯ã¼ããªã»ããã®ã¡ã¼ã«éä¿¡ç»é¢ |
GET | /users/password/edit | devise/passwords#edit | ãã¹ã¯ã¼ãåè¨å®ç»é¢ |
POST | /users/password | devise/passwords#create | ãã¹ã¯ã¼ããªã»ããã®ã¡ã¼ã«éä¿¡ |
PATCH/PUT | /users/password | devise/passwords#update | ãã¹ã¯ã¼ãåè¨å® |
ã«ã©ã
ð± Recoverableã¢ã¸ã¥ã¼ã«ã§ã¯ãusersãã¼ãã«ã«ä»¥ä¸ã®2ã¤ã®ã«ã©ã ãå¿ è¦ã«ãªããã
ã«ã©ã | æ¦è¦ |
---|---|
reset_password_token | ãã¹ã¯ã¼ããªã»ããã§å©ç¨ãããã¼ã¯ã³ã ä¸æã®ã©ã³ãã ãªãã¼ã¯ã³ãçæãããã ãã¹ã¯ã¼ããªã»ããã¡ã¼ã«ãããã¹ã¯ã¼ãåè¨å®ç»é¢ï¼ /users/password/edit ï¼ã¸ã¢ã¯ã»ã¹ããéã«ãã¦ã¼ã¶ã¼ãå¤å®ããã®ã«å©ç¨ããã |
reset_password_sent_at | ãã¹ã¯ã¼ããªã»ããã¡ã¼ã«éä¿¡æå»ã ãã¹ã¯ã¼ããªã»ããã¡ã¼ã«ã®æå¹æéã®å¤å®ã«å©ç¨ããã |
è¨å®
# config/initializers/devise.rb # ãã¹ã¯ã¼ããªã»ããæã«ãã¼ã«ãªãã«ã©ã ã config.reset_password_keys = [:email] # ãã¹ã¯ã¼ããªã»ããã®æå¹æéã config.reset_password_within = 6.hours # ãã¹ã¯ã¼ããªã»ããå¾ã«èªåãã°ã¤ã³ã config.sign_in_after_reset_password = true
ã¡ã½ãã
# ãã¹ã¯ã¼ããªã»ããã¡ã¼ã«éä¿¡ user.send_reset_password_instructions # ãã¹ã¯ã¼ããªã»ãã # user.reset_password(new_password, new_password_confirmation) user.reset_password('password123', 'password123') # reset_password_tokenãæå¹æéå ãã©ããããreset_password_sent_atã使ãå¤å® user.reset_password_period_valid? #=> true # tokenã使ã£ã¦userãåå¾ User.with_reset_password_token(token) #=> user
ã¡ã¼ã«
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#reset_password_instructions | ãã¹ã¯ã¼ããªã»ããã¡ã¼ã« |
åè
008 Validatableã¢ã¸ã¥ã¼ã«
ð± Validatableã¢ã¸ã¥ã¼ã«ã¯emailã¨passwordã®ããªãã¼ã·ã§ã³ãæä¾ããããValidatableã¢ã¸ã¥ã¼ã«ãå©ç¨ããã¨ããµã¤ã³ã¢ããã§ä¸æ£ãªemailã¨passwordãå ¥åããéã«ããªãã¼ã·ã§ã³ã¨ã©ã¼ã表示ãã¦ãããããã«ãªããã
ããªãã¼ã·ã§ã³é ç®
ð± emailã«å¯¾ãã¦ã¯ä»¥ä¸ã®3ã¤ã®ããªãã¼ã·ã§ã³ãè¨å®ãããã
# emailãåå¨ããã㨠validates_presence_of :email, if: :email_required? # emailãã¦ãã¼ã¯ã§ããã㨠validates_uniqueness_of :email, allow_blank: true, if: :email_changed? # emailãæ£è¦è¡¨ç¾ã«ãããããã㨠# ããã©ã«ãã®emailæ£è¦è¡¨ç¾ã¯`/\A[^@\s]+@[^@\s]+\z/` validates_format_of :email, with: email_regexp, allow_blank: true, if: :email_changed?
ð± passwordã«å¯¾ãã¦ã¯ä»¥ä¸ã®3ã¤ã®ããªãã¼ã·ã§ã³ãè¨å®ãããã
# passwordãåå¨ããã㨠validates_presence_of :password, if: :password_required? # passwordã¨password_confirmationãåè´ããã㨠validates_confirmation_of :password, if: :password_required? # passwordãæå®æåæ°ä»¥å ã§ããã㨠# ããã©ã«ãã¯6æåãã128æå validates_length_of :password, within: password_length, allow_blank: true
è¨å®
# config/initializers/devise.rb # passwordã®é·ãã # Rangeã§æå®ããã®å ´åã¯6æåãã128æåã config.password_length = 6..128 # emailããªãã¼ã·ã§ã³ã§å©ç¨ããæ£è¦è¡¨ç¾ config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
åè
009 Confirmableã¢ã¸ã¥ã¼ã«
ð± Confirmableã¢ã¸ã¥ã¼ã«ã¯ãµã¤ã³ã¢ããæã«æ¬ç»é²ç¨ã®ã¡ã¼ã«ãéä¿¡ãã¦ãç»é²ãããã¡ã¼ã«ã¢ãã¬ã¹ãå®éã«ã¦ã¼ã¶ã¼ã®ãã®ã§ããã確èªããæ©è½ãæä¾ãããããµã¤ã³ã¢ããæã«ä»®ç»é²ã«ãªã£ã¦ãã¡ã¼ã«å ã®ãªã³ã¯ãã¯ãªãã¯ããã¨æ¬ç»é²ã«ãªãããããããã¤ã ããConfirmableã¢ã¸ã¥ã¼ã«ã使ããªãå ´åã¯ãemailã¨passwordã§ã¦ã¼ã¶ã¼ç»é²ããæç¹ã§æ¬ç»é²ã«ãªããã
å°å ¥
ð± Confirmableã¢ã¸ã¥ã¼ã«ã¯ããã©ã«ãã§ç¡å¹ã«ãªã£ã¦ããã®ã§ãæå¹ã«ãã¦ãããã
ð± Userã¢ãã«ã§Confirmableã¢ã¸ã¥ã¼ã«ãæå¹ã«ãããã
# app/models/user.rb class User < ApplicationRecord # :confirmableã追å devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :confirmable end
ð± Confirmableã¢ã¸ã¥ã¼ã«ã§å¿ è¦ã¨ãªãã«ã©ã ã追å ãããã
$ rails g migration add_confirmable_columns_to_users invoke active_record create db/migrate/20201115225427_add_confirmable_columns_to_users.rb
# db/migrate/20201115225427_add_confirmable_columns_to_users.rb class AddConfirmableColumnsToUsers < ActiveRecord::Migration[6.0] def change change_table :users do |t| # Confirmableã«å¿ è¦ãªã«ã©ã t.string :confirmation_token t.datetime :confirmed_at t.datetime :confirmation_sent_at t.string :unconfirmed_email end add_index :users, :confirmation_token, unique: true end end
$ rails db:migrate
ð± ããã§å®äºã ãã
ð± å®éã«è©¦ãã¦ã¿ãããè¨å®ãåæ ãããããã«ãµã¼ãã¼ãåèµ·åãã¦ããã¾ãã¯ãµã¤ã³ã¢ãããããã
ð± ãµã¤ã³ã¢ããããã¨ãã¡ã¼ã«ãéã£ãã®ã§ããªã³ã¯ãã¯ãªãã¯ãã¦ã¢ã«ã¦ã³ããã¢ã¯ãã£ãã¼ããã¦ããçãªã¡ãã»ã¼ã¸ã表示ãããåæã«Confirmæ示ã¡ã¼ã«ãéä¿¡ããããã
ã¡ãã»ã¼ã¸
ã¡ã¼ã«
ð± ã¡ãªã¿ã«ãã®æç¹ã§ã¯ã¾ã ã¦ã¼ã¶ã¼ã¯ä»®ç»é²ã®ãããªç¶æ ãªã®ã§ãã°ã¤ã³ãããã¨ã¯ã§ããªããããã°ã¤ã³ãããã¨ããã¨ãããªã¨ã©ã¼ã¡ãã»ã¼ã¸ã表示ããããã
ð± Confirmæ示ã¡ã¼ã«ã®ãConfirm my accountããªã³ã¯ãã¯ãªãã¯ããã¨ãã¢ã«ã¦ã³ããConfirmããã¦ãã°ã¤ã³ã§ããããã«ãªããã
ã³ã³ããã¼ã©ã¼ã¨ã«ã¼ãã£ã³ã°
ð± Confirmableã¢ã¸ã¥ã¼ã«ã§ã¯Devise::ConfirmationsController
ã¨ããã³ã³ããã¼ã©ã¼ã¨ä»¥ä¸ã®3ã¤ã®ã¢ã¯ã·ã§ã³ãç¨æããããã
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/confirmation | devise/confirmations#show | confirmã ã¡ã¼ã«ã®ãªã³ã¯å ã¯ããã ã¯ã¨ãªãã©ã¡ã¼ã¿ã¼ã®confirmation_tokenãä¸è´ããªãã¨ã¢ã¯ã»ã¹ã§ããªãã |
GET | /users/confirmation/new | devise/confirmations#new | confirmæ示ã¡ã¼ã«åéä¿¡ç»é¢ã |
POST | /users/confirmation | devise/confirmations#create | confirmæ示ã¡ã¼ã«éä¿¡ã |
ð± /users/confirmation/new
ã¯confirmæ示åéä¿¡ç»é¢ã§ãããããconfirmæ示ã¡ã¼ã«ãåéä¿¡ã§ãããã
ã«ã©ã
ð± Confirmableã¢ã¸ã¥ã¼ã«ã§ã¯ãusersãã¼ãã«ã«ä»¥ä¸ã®4ã¤ã®ã«ã©ã ãå¿ è¦ã«ãªããã
ã«ã©ã | æ¦è¦ |
---|---|
confirmation_token | confirmããéã«å©ç¨ãããã¼ã¯ã³ã ä¸æã®ã©ã³ãã ãªãã¼ã¯ã³ãçæãããã confirmæ示ã¡ã¼ã«ããconfirmã¢ã¯ã·ã§ã³ï¼ /users/confirmattion ï¼ã¸ã¢ã¯ã»ã¹ããéã«ãã¦ã¼ã¶ã¼ãå¤å®ããã®ã«å©ç¨ããã |
confirmed_at | confirmãããæå»ã confirmæ¸ã¿ãã©ããã¯ãã®ã«ã©ã ãnilãã©ããã§å¤å®ããã |
confirmation_sent_at | confirmation_tokenä½ææå»ã |
unconfirmed_email | ã¾ã confirmããã¦ããªãã¡ã¼ã«ã¢ãã¬ã¹ã emailå¤æ´æã®confirmã§å©ç¨ããã config.unconfirmed_email = true ã®å ´åã ãå¿
è¦ãconfirmãããã¾ã§ã¯æ°ããã¯emailã¯ãã®ã«ã©ã ã«ä¿åãããconfirmæã«emailã®ã«ã©ã ã«ã³ãã¼ãããã |
è¨å®
# config/initializers/devise.rb # confirmãªãã§ãã°ã¤ã³ã§ããæéã # ãããè¨å®ããã¨ä¸å®æéã¯confirmåã§ããã°ã¤ã³ã§ããããã«ãªãã # nilã«è¨å®ããã¨ç¡æéã«ãã°ã¤ã³ã§ããããã«ãªãã # ããã©ã«ã㯠0.daysãï¼confirmãªãã«ã¯ãã°ã¤ã³ã§ããªããï¼ config.allow_unconfirmed_access_for = 2.days # confirmation_tokenã®æå¹æéã # ã¦ã¼ã¶ã¼ã¯ãã®æéå ã«confirmæ示ã¡ã¼ã«ã®ãªã³ã¯ãã¯ãªãã¯ããªãã¨ãããªãã # ããã©ã«ã㯠nilãï¼å¶éãªããï¼ config.confirm_within = 3.days # ãµã¤ã³ã¢ããæã ãã§ãªããemailå¤æ´æã«ãConfirmã¡ã¼ã«ãéä¿¡ããã # unconfirmed_emailã«ã©ã ãå¿ è¦ã config.reconfirmable = true # confirmã®ãã¼ã config.confirmation_keys = [:email]
ã¡ã½ãã
# confirmãã # å ·ä½çã«ã¯confirmed_atã«ç¾å¨æå»ãè¨å®ãã user.confirm # confirmæ¸ã¿ãªããtrue user.confirmed? # æåã§Confirmã¡ã¼ã«ãéä¿¡ user.send_confirmation_instructions
ã¡ã¼ã«
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#confirmation_instructions | confirmæ示ã¡ã¼ã« |
åè
010 Trackableã¢ã¸ã¥ã¼ã«
ð± Trackableã¢ã¸ã¥ã¼ã«ã¯ãã°ã¤ã³æã«IPã¢ãã¬ã¹ã»ãã°ã¤ã³æå»ã»ãã°ã¤ã³åæ°ãDBã«ä¿åããæ©è½ãæä¾ãããããã¼ã¿ã¯ãã ä¿åããã ãã§ãDeviseå é¨ã§ä½¿ãããã§ã¯ãªããã
å°å ¥
ð± Trackableã¢ã¸ã¥ã¼ã«ã¯ããã©ã«ãã§ç¡å¹ã«ãªã£ã¦ããã®ã§ãæå¹ã«ãã¦ãããã
ð± ã¾ãã¯Userã¢ãã«ã§Trackableã¢ã¸ã¥ã¼ã«ãæå¹ã«ãããã
# app/models/user.rb class User < ApplicationRecord # :trackableã追å devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :trackable end
ð± Trackableã¢ã¸ã¥ã¼ã«ã§å¿ è¦ã¨ãªãã«ã©ã ã追å ãããã
$ rails g migration add_trackable_columns_to_users invoke active_record create db/migrate/20201115004935_add_trackable_columns_to_users.rb
# db/migrate/20201115004935_add_trackable_columns_to_users.rb class AddTrackableColumnsToUsers < ActiveRecord::Migration[6.0] def change change_table :users do |t| # Trackableã«å¿ è¦ãªã«ã©ã t.integer :sign_in_count, default: 0, null: false t.datetime :current_sign_in_at t.datetime :last_sign_in_at t.string :current_sign_in_ip t.string :last_sign_in_ip end end end
$ rails db:migrate
ð± ããã§å®äºã ãããµã¼ãã¼ãåèµ·åãã¦ã¦ã¼ã¶ã¼ããã°ã¤ã³ããã¨ã追å ããã«ã©ã ã«èªåçã«ãã°ã¤ã³æ å ±ãä¿åããããã
user.sign_in_count #=> 1 user.current_sign_in_at #=> Sun, 15 Nov 2020 00:55:35 UTC +00:00
ã«ã©ã
ð± Trackableã¢ã¸ã¥ã¼ã«ã§ã¯ãusersãã¼ãã«ã«ä»¥ä¸ã®5ã¤ã®ã«ã©ã ãå¿ è¦ã«ãªããããã°ã¤ã³æã«ãããã®ã«ã©ã ã«ãã¼ã¿ãä¿åããããã
ã«ã©ã | æ¦è¦ |
---|---|
sign_in_count | ãã°ã¤ã³åæ° |
current_sign_in_at | ææ°ã®ãã°ã¤ã³æå» |
last_sign_in_at | 1ã¤åã®ãã°ã¤ã³æå» |
current_sign_in_ip | ææ°ã®ãã°ã¤ã³æIPã¢ãã¬ã¹ |
last_sign_in_ip | 1ã¤åã®ãã°ã¤ã³æIPã¢ãã¬ã¹ |
011 Timeoutableã¢ã¸ã¥ã¼ã«
ð± Timeoutableã¢ã¸ã¥ã¼ã«ã¯ä¸å®æéã¢ã¯ã»ã¹ããªãã¨å¼·å¶ãã°ã¢ã¦ããããæ©è½ãæä¾ãããã
å°å ¥
ð± Timeoutableã¢ã¸ã¥ã¼ã«ã¯ããã©ã«ãã§ç¡å¹ã«ãªã£ã¦ããã®ã§ãæå¹ã«ãã¦ãããã
ð± Userã¢ãã«ã§Timeoutableã¢ã¸ã¥ã¼ã«ãæå¹ã«ãããã
# app/models/user.rb class User < ApplicationRecord # :timeoutableã追å devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :timeoutable end
ð± 次ã«ã¿ã¤ã ã¢ã¦ãæéã®è¨å®ãè¡ãããä»åã¯åä½ç¢ºèªã®ããã«10ç§ã§ã¿ã¤ã ã¢ã¦ãã«ãªãããã«è¨å®ãããã
# config/initializers/devise.rb - #config.timeout_in = 30.minutes + config.timeout_in = 10.seconds
ð± ããã§å®äºã ãã
ð± å®éã«è©¦ãã¦ã¿ãããè¨å®ãåæ ãããããã«ãµã¼ãã¼ãåèµ·åãã¦ããã¦ã¼ã¶ã¼ããã°ã¤ã³ãã¦ãã10ç§éä½ãããã«æ¾ç½®ãã¦ããã¢ã¯ã»ã¹ããã¨ãå¼·å¶ãã°ã¢ã¦ãã«ãªããã°ã¤ã³ç»é¢ã«ãªãã¤ã¬ã¯ãããããã
ð± Timeoutableã¢ã¸ã¥ã¼ã«ã¯ããã°ã¤ã³å¾ã«ã¦ã¼ã¶ã¼ãã¢ã¯ã»ã¹ãã度ã«ãsessionã«ã¢ã¯ã»ã¹æå»ãä¿åãã¦ãããã ãããã¦ååã®ãªã¯ã¨ã¹ãæå»ã¨ä»åã®ãªã¯ã¨ã¹ãæå»ãæ¯è¼ãã¦ãconfig.timeout_in
ï¼ã¿ã¤ã ã¢ã¦ãæéï¼ãè¶
ãã¦ããå ´åã«ãã°ã¢ã¦ãããã¦ãããã
è¨å®
# config/initializers/devise.rb # ã¿ã¤ã ã¢ã¦ãæé config.timeout_in = 30.minutes
ã¡ã½ãã
# ã¿ã¤ã ã¢ã¦ããªãtrue user.timedout?(Time.current)
åè
012 Lockableã¢ã¸ã¥ã¼ã«
ð± Lockableã¢ã¸ã¥ã¼ã«ã¯ãã°ã¤ã³æã«æå®åæ°ãã¹ã¯ã¼ããééããã¨ã¢ã«ã¦ã³ããããã¯ããæ©è½ãæä¾ãããã
å°å ¥
ð± Lockableã¢ã¸ã¥ã¼ã«ã¯ããã©ã«ãã§ç¡å¹ã«ãªã£ã¦ããã®ã§ãæå¹ã«ãã¦ãããã
ð± Userã¢ãã«ã§Lockableã¢ã¸ã¥ã¼ã«ãæå¹ã«ãããã
# app/models/user.rb class User < ApplicationRecord # :lockableã追å devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :lockable end
ð± Lockableã¢ã¸ã¥ã¼ã«ã§å¿ è¦ã¨ãªãã«ã©ã ã追å ãããã
$ rails g migration add_lockable_columns_to_users invoke active_record create db/migrate/20201115111752_add_lockable_columns_to_users.rb
# db/migrate/20201115111752_add_lockable_columns_to_users.rb class AddTrackableColumnsToUsers < ActiveRecord::Migration[6.0] def change change_table :users do |t| # Lockableã«å¿ è¦ãªã«ã©ã t.integer :failed_attempts, default: 0, null: false t.string :unlock_token t.datetime :locked_at end add_index :users, :unlock_token, unique: true end end
$ rails db:migrate
ð± 次ã«ãã°ã¤ã³ã®ä¸é試è¡åæ°ã®è¨å®ãè¡ãããä»åã¯åä½ç¢ºèªã®ããã«2åãã°ã¤ã³ã«å¤±æãããããã¯ããããã«è¨å®ãããã
# config/initializers/devise.rb - # config.maximum_attempts = 20 + config.maximum_attempts = 2
ð± ããã§å®äºã ãã
ð± å®éã«è©¦ãã¦ã¿ãããè¨å®ãåæ ãããããã«ãµã¼ãã¼ãåèµ·åãã¦ãããã°ã¤ã³ã§2åãã¹ã¯ã¼ããééããã¨ãã¢ã«ã¦ã³ããããã¯ããã¾ããããçãªã¨ã©ã¼ã¡ãã»ã¼ã¸ã表示ããã¦ããã以éã¯æ£ãããã¹ã¯ã¼ããå ¥åãã¦ããã°ã¤ã³ã§ããªããªããã
ð± ã¢ã«ã¦ã³ãããã¯æã«ã¯ãã¦ã¼ã¶ã¼ã«ä»¥ä¸ã®ãããªã¢ã³ããã¯æ示ã¡ã¼ã«ãéä¿¡ããããã
ð± ã¦ã¼ã¶ã¼ã¯ãã®ã¡ã¼ã«ã®ãUnlock my accountããªã³ã¯ãã¯ãªãã¯ããã¨ãã¢ã«ã¦ã³ããã¢ã³ããã¯ããã¦ãåã³ãã°ã¤ã³ã§ããããã«ãªããã
ã¡ã¼ã«ã§ã¯ãªãä¸å®æéçµéã§ã¢ã³ããã¯ããã
ð± Lockableã¢ã¸ã¥ã¼ã«ã§ã¯ã¡ã¼ã«ã§ã¢ã³ããã¯ããæ¹æ³ä»¥å¤ã«ãä¸å®æéçµéã§ã¢ã³ããã¯ããæ¹æ³ãæä¾ãã¦ãããã以ä¸ã®è¨å®ãè¡ãã¨ã¡ã¼ã«ã§ã¯ãªãæéçµéã§ã¢ã³ããã¯ã§ãããã
# config/initializers/devise.rb - # config.unlock_strategy = :email + config.lock_strategy = :time
ð± 次ã«ã¢ã³ããã¯ã¾ã§ã®æéã®è¨å®ãè¡ãããä»åã¯åä½ç¢ºèªã®ããã«10ç§ã§ã¢ã³ããã¯ããããã«è¨å®ãããã
# config/initializers/devise.rb - # config.unlock_in = 1.hour + config.unlock_in = 10.seconds
ð± ããã§å®äºã ãã
ð± å®éã«è©¦ãã¦ã¿ãããè¨å®ãåæ ãããããã«ãµã¼ãã¼ãåèµ·åãã¦ãããã°ã¤ã³ã§2åãã¹ã¯ã¼ããééããã¨ã¢ã«ã¦ã³ããããã¯ããããããã®å¾10ç§å¾ ã¤ã¨ãã¢ã«ã¦ã³ããèªåã§ã¢ã³ããã¯ããã¦ãåã³ãã°ã¤ã³ã§ããããã«ãªããã
ã³ã³ããã¼ã©ã¼ã¨ã«ã¼ãã£ã³ã°
ð± Lockableã¢ã¸ã¥ã¼ã«ã§ã¯Devise::UnlocksController
ã¨ããã³ã³ããã¼ã©ã¼ã¨ä»¥ä¸ã®3ã¤ã®ã¢ã¯ã·ã§ã³ãç¨æããããã
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/unlock | devise/unlocks#show | ã¢ã³ããã¯ã ã¡ã¼ã«ã®ãªã³ã¯å ã¯ããã ã¯ã¨ãªãã©ã¡ã¼ã¿ã¼ã®unlock_tokenãä¸è´ããªãã¨ã¢ã¯ã»ã¹ã§ããªãã |
GET | /users/unlock/new | devise/unlocks#new | ã¢ã³ããã¯æ示ã¡ã¼ã«åéä¿¡ç»é¢ã |
POST | /users/unlock | devise/unlocks#create | ã¢ã³ããã¯æ示ã¡ã¼ã«éä¿¡ã |
ð± /users/unlock/new
ã¯ã¢ã³ããã¯æ示ã¡ã¼ã«åéä¿¡ç»é¢ã§ãããããã¢ã³ããã¯æ示ã¡ã¼ã«ãåéä¿¡ã§ãããã
ã«ã©ã
ð± Lockableã¢ã¸ã¥ã¼ã«ã§ã¯ãusersãã¼ãã«ã«ä»¥ä¸ã®3ã¤ã®ã«ã©ã ãå¿ è¦ã«ãªããã
ã«ã©ã | æ¦è¦ |
---|---|
failed_attempts | 失æåæ°ãconfig.lock_strategy ã:failed_attempts ã®å ´åã«ã ãå¿
è¦ã |
unlock_token | ã¡ã¼ã«ããã¢ã³ããã¯ããéã«å©ç¨ããtokenã ä¸æã®ã©ã³ãã ãªãã¼ã¯ã³ãçæãããã ã¢ã³ããã¯æ示ã¡ã¼ã«ããã¢ã³ããã¯ã¢ã¯ã·ã§ã³ï¼ /users/unlock ï¼ã¸ã¢ã¯ã»ã¹ããéã«ãã¦ã¼ã¶ã¼ãå¤å®ããã®ã«å©ç¨ãããconfig.unlock_strategy ã:email ã:both ã®å ´åã«ã ãå¿
è¦ã |
locked_at | ããã¯æå»ã ãããnullã§ãªãå ´åã«ããã¯ç¶æ ã¨ã¿ãªãããã |
è¨å®
# config/initializers/devise.rb # ããã¯æ¹æ³ # - failed_attempts: æå®åæ°ééããããã㯠# - none: èªåããã¯ã¯ãªãã§ããµã¼ã管çè ãæåã§ãã㯠config.lock_strategy = :failed_attempts # ã¢ã³ããã¯ã®ãã¼ config.unlock_keys = [:email] # ã¢ã³ããã¯æ¹æ³ # - email: ã¡ã¼ã«ã§ã¢ã³ããã¯ã®ãªã³ã¯ãéä¿¡ï¼config.maximum_attemptsã¨ä¸ç·ã«ä½¿ãï¼ # - time: æ°æéå¾ã«ã¢ã³ããã¯ï¼config.unlock_inã¨ä¸ç·ã«ä½¿ãï¼ # - both: emailã¨timeã®ä¸¡æ¹ # - none: èªåã¢ã³ããã¯ã¯ãªãã§ããµã¼ã管çè ãæåã§ã¢ã³ãã㯠config.unlock_strategy = :both # ããã¯ã¾ã§ã®åæ° config.maximum_attempts = 20 # ã¢ã³ããã¯ã¾ã§ã®æéï¼`config.unlock_strategy = :time`ã®å ´åï¼ config.unlock_in = 1.hour # ããã¯åã«è¦åãã config.last_attempt_warning = true
ã¡ã½ãã
# ããã¯(ã¡ã¼ã«éä¿¡ããã) user.lock_access! # ããã¯(ã¡ã¼ã«éä¿¡ããªã) user.lock_access!(send_instructions: false) # ã¢ã³ãã㯠user.unlock_access! # ã¢ã³ããã¯ã®ã¡ã¼ã«éä¿¡ user.resend_unlock_instructions
ã¡ã¼ã«
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#unlock_instructions | ã¢ã«ã¦ã³ãã¢ã³ããã¯æ示ã¡ã¼ã« |
åè
013 Omniauthableã¢ã¸ã¥ã¼ã«
ð± Omniauthableã¢ã¸ã¥ã¼ã«ã¯Deviseã¨OmniAuth gemã¨ã®é£æºæ©è½ãæä¾ããããOmniauthableã¢ã¸ã¥ã¼ã«ã使ããã¨ã§ãã¦ã¼ã¶ã¼ã¯Twitterã¢ã«ã¦ã³ããGoogleã¢ã«ã¦ã³ããªã©ã§ãã°ã¤ã³ã§ããããã«ãªããã
OmniAuthã¨ã¯ï¼
ð¦ð» OmniAuthã£ã¦ãªã«ï¼
ð± ããããã£ããããã¨ãOAuthãå©ç¨ãã¦ãTwitterãGoogleã®ã¢ã«ã¦ã³ãã§ã¢ããªã±ã¼ã·ã§ã³ã«ãã°ã¤ã³ã§ããããã«ããgemã ããããå°ãã¡ããã¨èª¬æããã¨ãOmniAuthã¯è¤æ°ãããã¤ãã¼ãä»ããèªè¨¼ãæ¨æºåããgemã ããOmniAuthã¯Strategyã¨ããä»çµã¿ãæä¾ãããã¨ã§ãå¥åã®èªè¨¼ãå ±éã®ã¤ã³ã¿ã¼ãã§ã¼ã¹ã§èªè¨¼ã§ããããã«ãªããã ãä¾ãã°Twitterã¢ã«ã¦ã³ãã¨Googleã¢ã«ã¦ã³ãã§ãã°ã¤ã³ã§ãããããªã¢ããªã±ã¼ã·ã§ã³ãèãã¦ã¿ã¦ãããã®ã¨ãTwitterã¨Googleã§ãããã¤ãã¼ãç°ãªããã ãã©ãTwitterã«å¯¾å¿ããStrategyã¨Googleã«å¯¾å¿ããStrategyãç¨æããã°ãOmniAuthãä»ãã¦åãã¤ã³ã¿ã¼ãã§ã¼ã¹ã§èªè¨¼ãã§ããããã«ãªããã
ð± Strategyã¯èªåã§ç¨æãããã¨ãã§ãããã©ã主è¦ãªãããã¤ãã¼ã«å¯¾å¿ããStrategyã¯æ¢ã«gemã¨ãã¦ç¨æããã¦ãããããããã使ãã°OKã ãï¼ List of Strategies · omniauth/omniauth Wiki · GitHub ï¼ããããã®Strategyã®gemã¯ãã©ãã¯ããã¯ã¹ã¨ãã¦å©ç¨ãããã¨ãã§ãã¦ãOAuthã®ãããªè¤éãªããã¼ãèªåã§å®è£
ãããã¨ãªããç°¡åã«OAuthãå®ç¾ã§ããããã«ãªã£ã¦ããããStrategyã¯Rackããã«ã¦ã§ã¢ã¨ãã¦å®è£
ããã¦ãomniauth-<ãããã¤ãã¼å>
ã®ãããªå称ã®gemã¨ãã¦æä¾ããããã
ð± OmniAuthãOmniauthableã¢ã¸ã¥ã¼ã«çµç±ã§ä½¿ãå ´åã¯ãomniauth-twitter
ãomniauth-google-oauth2
ãªã©ã®OAuthãå©ç¨ãããã°ã¤ã³ãå®è£
ãããã¨ãã»ã¨ãã©ã ãããã OmniAuthèªä½ã¯OAuthã ãã§ãªãemail/passwordã«ããèªè¨¼ãBasicèªè¨¼ãªãããStrategyã¨ãã¦å©ç¨ã§ããããã«ãªã£ã¦ãããã
ð± Twitterã§ãããGoogleã§ãããOmniAuthã®ä½¿ãæ¹ã¯ã ãããåãã ãããã ãããã¤ãã¼ããåå¾ã§ãããã¼ã¿ï¼emailãåå¾ã§ãããã§ããªãã£ããï¼ãAPI keyã®åå¾æ¹æ³ãªã©ãç´°ããç¹ã¯å¤ãã£ã¦ãããã
åè
- GitHub - omniauth/omniauth: OmniAuth is a flexible authentication system utilizing Rack middleware.
- OmniAuth OAuth2 ã使ã£ã¦ OAuth2 ã®ã¹ãã©ãã¸ã¼ãä½ãã¨ãã«ç¥ã£ã¦ããã¨å¹¸ãã«ãªãããããããªãã㨠- Qiita
OmniAuth Twitter - Twitterã¢ã«ã¦ã³ãã«ãããã°ã¤ã³
ð± omniauth-twitter
gemã使ãã°Twitterã¢ã«ã¦ã³ãã§ãã°ã¤ã³ã§ããããã«ãªããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
- GitHub - arunagw/omniauth-twitter: OmniAuth strategy for Twitter
- [Rails] deviseã®ä½¿ãæ¹ï¼rails6çï¼ - Qiita
- [Rails] Facebook/Twitter/Googleã§ã®ã¦ã¼ã¶ã¼ç»é²ãDevise & Omniauthã使ã£ã¦çéã§å®è£ ãã - Qiita
OmniAuth Google OAuth2 - Googleã¢ã«ã¦ã³ãã«ãããã°ã¤ã³
ð± omniauth-google-oauth2
gemã使ãã°Googleã¢ã«ã¦ã³ãã§ãã°ã¤ã³ã§ããããã«ãªããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
- GitHub - zquestz/omniauth-google-oauth2: Oauth2 strategy for Google
- çéã!! gem omniauth-google-oauth2 ã§èªè¨¼ããã - Qiita
- [Rails] Facebook/Twitter/Googleã§ã®ã¦ã¼ã¶ã¼ç»é²ãDevise & Omniauthã使ã£ã¦çéã§å®è£ ãã - Qiita
OmniAuth Facebook - Facebookã¢ã«ã¦ã³ãã«ãããã°ã¤ã³
ð± omniauth-facebook
gemã使ãã°Facebookã¢ã«ã¦ã³ãã§ãã°ã¤ã³ã§ããããã«ãªããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
- GitHub - simi/omniauth-facebook: Facebook OAuth2 Strategy for OmniAuth
- [Devise How-To] OmniAuth: æ¦è¦ï¼ç¿»è¨³ï¼ï½TechRachoï¼ããã¯ã©ããã§ï¼ãã¨ã³ã¸ãã¢ã®ãï¼ãããï¼ãã«ãï½BPSæ ªå¼ä¼ç¤¾
- railsã§omniauth-facebookã使ã£ã¦Facebookãã°ã¤ã³ãå®è£ ããæ¹æ³ - Qiita
第3ç« ãã¥ã¼ãã«ã¹ã¿ãã¤ãºãã
014 ãã¥ã¼ãã«ã¹ã¿ãã¤ãºãã
ð± Deviseã§å©ç¨ããããã¥ã¼ãã¡ã¤ã«ã®åªå é ä½ã¯ä»¥ä¸ã®ããã«ãªã£ã¦ããã
- ã¢ããªå
ã®deviseãã¥ã¼ï¼
devise/sessions/new.html.erb
ï¼ - gemå
ã®deviseãã¥ã¼ï¼
devise/sessions/new.html.erb
ï¼
ð± ããã©ã«ãã§ã¯ãã¥ã¼ãã¡ã¤ã«ã¯gemã®ä¸ã«ãã£ã¦ãããã使ãããã«ãªã£ã¦ãããã ããªã®ã§ãã¥ã¼ãã«ã¹ã¿ãã¤ãºãããå ´åã¯ãgemã®ä¸ã®ãã¥ã¼ãã¡ã¤ã«ãèªåã®ã¢ããªã«ã³ãã¼ãã¦ããããããèªåã§ä¿®æ£ãã¦ããã°OKã ãã
ð± ã¾ãã¯èªåã®ã¢ããªã«ãã¥ã¼ãã¡ã¤ã«ãã³ãã¼ãã¦ãã以ä¸ã®ã³ãã³ãæã¦ã°ãã¥ã¼ãã¡ã¤ã«ãã³ãã¼ããããã
$ rails g devise:views invoke Devise::Generators::SharedViewsGenerator exist app/views/devise/shared create app/views/devise/shared/_error_messages.html.erb create app/views/devise/shared/_links.html.erb invoke form_for exist app/views/devise/confirmations create app/views/devise/confirmations/new.html.erb exist app/views/devise/passwords create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb exist app/views/devise/registrations create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb exist app/views/devise/sessions create app/views/devise/sessions/new.html.erb exist app/views/devise/unlocks create app/views/devise/unlocks/new.html.erb invoke erb exist app/views/devise/mailer create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/email_changed.html.erb create app/views/devise/mailer/password_change.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erb
ð± ãã¨ã¯ä½æããããã¥ã¼ãèªåã§ä¿®æ£ãã¦ããã°OKã ãã
ð± ã¡ãªã¿ã«ãUserã¨Adminã®ããã«è¤æ°ã¢ãã«ãå©ç¨ããã®ã§ãªããã°ãããããScopeæå®ããå¿ è¦ã¯ãªããã
# ãããªæãã§users Scopeãæå®ãã¦ä½æãããã¨ãå¯è½ # ãã config.scoped_viewsãè¨å®ãããã«ã¹ã¿ã ã³ã³ããã¼ã©ã¼ãå¿ é ã ã£ããè²ã é¢åã # è¤æ°ã¢ãã«ãå©ç¨ããã®ã§ãªããã°ãããããScopeæå®ããå¿ è¦ã¯ãªããã $ rails g devise:views users invoke Devise::Generators::SharedViewsGenerator create app/views/users/shared create app/views/users/shared/_error_messages.html.erb create app/views/users/shared/_links.html.erb invoke form_for create app/views/users/confirmations create app/views/users/confirmations/new.html.erb create app/views/users/passwords create app/views/users/passwords/edit.html.erb create app/views/users/passwords/new.html.erb create app/views/users/registrations create app/views/users/registrations/edit.html.erb create app/views/users/registrations/new.html.erb create app/views/users/sessions create app/views/users/sessions/new.html.erb create app/views/users/unlocks create app/views/users/unlocks/new.html.erb invoke erb create app/views/users/mailer create app/views/users/mailer/confirmation_instructions.html.erb create app/views/users/mailer/email_changed.html.erb create app/views/users/mailer/password_change.html.erb create app/views/users/mailer/reset_password_instructions.html.erb create app/views/users/mailer/unlock_instructions.html.erb
015 ã¬ã¤ã¢ã¦ããã³ãã¬ã¼ããã«ã¹ã¿ãã¤ãºãã
Deviseå ¨ä½ã®ã¬ã¤ã¢ã¦ããã³ãã¬ã¼ããç¨æããå ´å
ð± Deviseã¯ããã©ã«ãã§ã¯é常ã®ãã¥ã¼ã¨åããã¬ã¤ã¢ã¦ããã³ãã¬ã¼ãã«application.html.erb
ãå©ç¨ããããDeviseã®ã¬ã¤ã¢ã¦ããã³ãã¬ã¼ããå¤æ´ãããå ´åã¯app/views/layouts/devise.html.erb
ãç¨æããã°èªåã§ãã£ã¡ã使ã£ã¦ãããã®ã§ãapp/views/layouts/devise.html.erb
ãç¨æããã°OKã ãã
ã³ã³ããã¼ã©ã¼æ¯ã»ã¢ã¯ã·ã§ã³æ¯ã«ã¬ã¤ã¢ã¦ããã³ãã¬ã¼ããç¨æããå ´å
ð± ã³ã³ããã¼ã©ã¼æ¯ã»ã¢ã¯ã·ã§ã³æ¯ã«ã¬ã¤ã¢ã¦ããã³ãã¬ã¼ããç¨æãããå ´åã¯ãåã³ã³ããã¼ã©ã¼ã§layout
ã¡ã½ãããå©ç¨ãããã
ð± ã¾ãã¸ã§ãã¬ã¼ã¿ã¼ãå©ç¨ãã¦ã«ã¹ã¿ã ã³ã³ããã¼ã©ã¼ãä½æãã¦ãã
$ rails g devise:controllers users create app/controllers/users/confirmations_controller.rb create app/controllers/users/passwords_controller.rb create app/controllers/users/registrations_controller.rb create app/controllers/users/sessions_controller.rb create app/controllers/users/unlocks_controller.rb create app/controllers/users/omniauth_callbacks_controller.rb
ð± ã³ã³ããã¼ã©ã¼ã§layout
ã¡ã½ããã使ã£ã¦ã¬ã¤ã¢ã¦ããã³ãã¬ã¼ããæå®ãã¦ãã
# app/controllers/users/registerations_controller.rb class User::RegistrationsController < Devise::RegistrationsController # RegistrationsControllerã®editã¢ã¯ã·ã§ã³ã§ã¯your_layoutãã¡ã¤ã«ã使ãããã«ãã layout "your_layout", only: [:edit] end
ð± å¥ã®æ¹æ³ã¨ãã¦ãã«ã¹ã¿ã ã³ã³ããã¼ã©ã¼ãä½æããã«è¨å®ãã¡ã¤ã«ã§æå®ãããã¨ãå¯è½ã ãã
# config/application.rb config.to_prepare do # ã³ã³ããã¼ã©ã¼æ¯ã«ã¬ã¤ã¢ã¦ããã¡ã¤ã«ãæå®ã§ãã Devise::SessionsController.layout "your_layout" Devise::RegistrationsController.layout "your_layout" Devise::ConfirmationsController.layout "your_layout" Devise::UnlocksController.layout "your_layout" Devise::PasswordsController.layout "your_layout" end
016 ããªãã¼ã·ã§ã³ã¨ã©ã¼ã®è¡¨ç¤ºãã«ã¹ã¿ãã¤ãºãã
ð± Deviseã§ã¯ããªãã¼ã·ã§ã³ã¨ã©ã¼ã®è¡¨ç¤ºããã¼ã·ã£ã«ã¨ãã¦ããã©ã«ãã§ç¨æããã¦ãããã
ð± ä¾ãã°ãµã¤ã³ã¢ããç»é¢ã§ã¯ãããªæãã§ããªãã¼ã·ã§ã³ã¨ã©ã¼è¡¨ç¤ºã®ãã¼ã·ã£ã«ãrenderãã¦ãããã
# app/views/devise/registrations/new.html.erb <h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <!-- ãã --> <%= render "devise/shared/error_messages", resource: resource %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <div class="field"> <%= f.label :password %> <% if @minimum_password_length %> <em>(<%= @minimum_password_length %> characters minimum)</em> <% end %><br /> <%= f.password_field :password, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %>
ð± ããªãã¼ã·ã§ã³ã¨ã©ã¼è¡¨ç¤ºã®ãã¼ã·ã£ã«ã§ã¯resource
ã®ã¨ã©ã¼ã表示ãã¦ããããresourceã¯Userã¤ã³ã¹ã¿ã³ã¹ã ãã
# app/views/devise/shared/_error_messages.html.erb <!-- resourceï¼Userã¤ã³ã¹ã¿ã³ã¹ï¼ã«ããªãã¼ã·ã§ã³ã¨ã©ã¼ãããã°ãã¨ã©ã¼å 容ã表示 --> <% if resource.errors.any? %> <div id="error_explanation"> <h2> <%= I18n.t("errors.messages.not_saved", count: resource.errors.count, resource: resource.class.model_name.human.downcase) %> </h2> <ul> <% resource.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %>
ð± ããªãã¼ã·ã§ã³ã¨ã©ã¼ã®è¡¨ç¤ºãã«ã¹ã¿ãã¤ãºãããå ´åã¯ããã®_error_messages.html.erb
ãã«ã¹ã¿ãã¤ãºããã°OKã ãã
ð± ã¡ãªã¿ã«å¤ããã¼ã¸ã§ã³ã ã¨_error_messages.html.erb
ãå©ç¨ããã«ãdevise_error_messages!
ã¨ããã¡ã½ãããå©ç¨ãã¦ããå ´åããããããã®å ´åã¯_error_messages.html.erb
ãèªåã§ç¨æããããdevise_error_messages!
ããªã¼ãã¼ã©ã¤ããããã¨ã§ã«ã¹ã¿ãã¤ãºã§ãããã詳ããã¯ãã¡ããåèã«ãã¦ã -> Override devise_error_messages! for views · heartcombo/devise Wiki · GitHub
åè
017 ãã¥ã¼ãHamlã«ãã
ð± ã¾ãã¯èªåã®ã¢ããªã«ãã¥ã¼ãã¡ã¤ã«ãã³ãã¼ãã¦ãã
$ rails g devise:views invoke Devise::Generators::SharedViewsGenerator exist app/views/devise/shared create app/views/devise/shared/_error_messages.html.erb create app/views/devise/shared/_links.html.erb invoke form_for exist app/views/devise/confirmations create app/views/devise/confirmations/new.html.erb exist app/views/devise/passwords create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb exist app/views/devise/registrations create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb exist app/views/devise/sessions create app/views/devise/sessions/new.html.erb exist app/views/devise/unlocks create app/views/devise/unlocks/new.html.erb invoke erb exist app/views/devise/mailer create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/email_changed.html.erb create app/views/devise/mailer/password_change.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erb
ð± Erbãã¡ã¤ã«ãHamlãã¡ã¤ã«ã«å¤æããããã«ãhtml2haml
ã¨ãããã¼ã«ãå©ç¨ããããhtml2haml
ãã¤ã³ã¹ãã¼ã«ãã¦ããä¸åº¦ãã使ããªãã®ã§gem
ã³ãã³ãã§ã¤ã³ã¹ãã¼ã«ãã¡ãã£ã¦OKã ãã
$ gem install html2haml
ð± å ¨ã¦ã®Erbãã¡ã¤ã«ãHamlã«å¤æãããã
# å ¨Erbãã¡ã¤ã«ãHamlãã¡ã¤ã«ã«å¤æ $ find ./app/views/devise -name \*.erb -print | sed 'p;s/.erb$/.haml/' | xargs -n2 html2haml # å ¨Erbãã¡ã¤ã«ãåé¤ $ rm app/views/devise/**/*.erb
åè
018 ãã¥ã¼ãSlimã«ãã
ð± ã¾ãã¯èªåã®ã¢ããªã«ãã¥ã¼ãã¡ã¤ã«ãã³ãã¼ãã¦ãã
$ rails g devise:views invoke Devise::Generators::SharedViewsGenerator exist app/views/devise/shared create app/views/devise/shared/_error_messages.html.erb create app/views/devise/shared/_links.html.erb invoke form_for exist app/views/devise/confirmations create app/views/devise/confirmations/new.html.erb exist app/views/devise/passwords create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb exist app/views/devise/registrations create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb exist app/views/devise/sessions create app/views/devise/sessions/new.html.erb exist app/views/devise/unlocks create app/views/devise/unlocks/new.html.erb invoke erb exist app/views/devise/mailer create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/email_changed.html.erb create app/views/devise/mailer/password_change.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erb
ð± Erbãã¡ã¤ã«ãSlimãã¡ã¤ã«ã«å¤æããããã«ãhtml2slim
ã¨ãããã¼ã«ãå©ç¨ããããhtml2slim
ãã¤ã³ã¹ãã¼ã«ãã¦ããä¸åº¦ãã使ããªãã®ã§gem
ã³ãã³ãã§ã¤ã³ã¹ãã¼ã«ãã¡ãã£ã¦OKã ãã
$ gem install html2slim
ð± å ¨ã¦ã®Erbãã¡ã¤ã«ãSlimã«å¤æãããã
# å ¨Erbãã¡ã¤ã«ãSlimãã¡ã¤ã«ã«å¤æ $ find ./app/views/devise -name \*.erb -print | sed 'p;s/.erb$/.slim/' | xargs -n2 html2slim # å ¨Erbãã¡ã¤ã«ãåé¤ $ rm app/views/devise/**/*.erb
019 Bootstrap4ç¨ã®ãã¥ã¼ãå©ç¨ãã
ð± devise-bootstrap-views
ã¨ããgemã使ãã¨Bootstrapç¨ã®ãã¥ã¼ãgenerateã§ããããã«ãªããã
ð± æ¥æ¬èªã使ãããå ´åã¯ãdevise-i18n
ã¨ããI18n対å¿ã®Deviseãã¥ã¼ãä½æããgemãä¸ç·ã«å
¥ããã¨ãããã
# Gemfile gem 'devise-i18n' gem 'devise-bootstrap-views'
$ bundle install
ð± ãã¥ã¼ã®ã¸ã§ãã¬ã¼ã¿ã¼ã§Bootstrapãã³ãã¬ã¼ããæå®ãã¦ãã
$ rails g devise:views:bootstrap_templates create app/views/devise create app/views/devise/confirmations/new.html.erb create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb create app/views/devise/sessions/new.html.erb create app/views/devise/shared/_links.html.erb create app/views/devise/unlocks/new.html.erb
ð± ãããªæãã§Bootstrapã®ã¯ã©ã¹ãå©ç¨ãããã¥ã¼ãã¡ã¤ã«ãä½æããããã
# app/views/devise/sessions/new.html.erb <h1><%= t('.sign_in') %></h1> <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> <!-- form-groupã¨ãã®Bootstrapç¨ã®classãä»ä¸ããã¦ããã--> <div class="form-group"> <%= f.label :email %> <%= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control' %> </div> <div class="form-group"> <%= f.label :password %> <%= f.password_field :password, autocomplete: 'current-password', class: 'form-control' %> </div> <% if devise_mapping.rememberable? %> <div class="form-group form-check"> <%= f.check_box :remember_me, class: 'form-check-input' %> <%= f.label :remember_me, class: 'form-check-label' do %> <%= resource.class.human_attribute_name('remember_me') %> <% end %> </div> <% end %> <div class="form-group"> <%= f.submit t('.sign_in'), class: 'btn btn-primary' %> </div> <% end %> <%= render 'devise/shared/links' %>
ð± ãã°ã¤ã³ç»é¢ã®è¦ãç®ãBootstrapã«ãªã£ã¦ããã
ð± devise-bootstrap-views
ã¯ããã¾ã§Bootstrap4ç¨ã®ãã¥ã¼ãç¨æãã¦ãããã ãã ããBootstrap4èªä½ã¯èªåã§ã»ããã¢ããããå¿
è¦ãããã®ã§æ³¨æãã¦ãã
åè
第4ç« ã³ã³ããã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºãã
020 ã³ã³ããã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºãã
ð± ã³ã³ããã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºããããã«ã¯ãã¸ã§ãã¬ã¼ã¿ã¼ãå©ç¨ãã¦ã³ã³ããã¼ã©ã¼ãçæããå¿ è¦ããããã
$ rails g devise:controllers users create app/controllers/users/confirmations_controller.rb create app/controllers/users/passwords_controller.rb create app/controllers/users/registrations_controller.rb create app/controllers/users/sessions_controller.rb create app/controllers/users/unlocks_controller.rb create app/controllers/users/omniauth_callbacks_controller.rb =============================================================================== Some setup you must do manually if you haven't yet: Ensure you have overridden routes for generated controllers in your routes.rb. For example: Rails.application.routes.draw do devise_for :users, controllers: { sessions: 'users/sessions' } end ===============================================================================
ð± çæãããã³ã³ããã¼ã©ã¼ã¯ãããªæãã ããDeviseã®ã³ã³ããã¼ã©ã¼ã®ãµãã¯ã©ã¹ã«ãªã£ã¦ãããããã¥ã¼ã®çæã§ã¯gemå ã®ãã¥ã¼ããã®ã¾ã¾ã³ãã¼ããã®ã«å¯¾ãã¦ãã³ã³ããã¼ã©ã¼ã®çæã§ã¯gemå ã®ã³ã³ããã¼ã©ã¼ãç¶æ¿ããã¯ã©ã¹ãçæãããããã¥ã¼ã®çæã¨ã¯ã¡ãã£ã¨éãã®ã§æ³¨æãã¦ãã
# app/controllers/users/sessions_controller.rb # frozen_string_literal: true class Users::SessionsController < Devise::SessionsController # before_action :configure_sign_in_params, only: [:create] # GET /resource/sign_in # def new # super # end # POST /resource/sign_in # def create # super # end # DELETE /resource/sign_out # def destroy # super # end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_in_params # devise_parameter_sanitizer.permit(:sign_in, keys: [:attribute]) # end end
ð± ã«ã¼ãã£ã³ã°ãå¤æ´ããå¿
è¦ãããããããã©ã«ãã ã¨ãããªæãã§Devise gemå
ã®devise
åå空éã®ã³ã³ããã¼ã©ã¼ãå©ç¨ããããã«ãªã£ã¦ãããã
# config/routes.rb devise_for :users
$ rails routes Prefix Verb URI Pattern Controller#Action new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy new_user_password GET /users/password/new(.:format) devise/passwords#new edit_user_password GET /users/password/edit(.:format) devise/passwords#edit user_password PATCH /users/password(.:format) devise/passwords#update PUT /users/password(.:format) devise/passwords#update POST /users/password(.:format) devise/passwords#create cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel new_user_registration GET /users/sign_up(.:format) devise/registrations#new edit_user_registration GET /users/edit(.:format) devise/registrations#edit user_registration PATCH /users(.:format) devise/registrations#update PUT /users(.:format) devise/registrations#update DELETE /users(.:format) devise/registrations#destroy POST /users(.:format) devise/registrations#create
ð± ãã£ãçæããã¢ããªå
ã®users
åå空éã®ã³ã³ããã¼ã©ã¼ãå©ç¨ããããã«å¤æ´ããããã³ã³ããã¼ã©ã¼æ¯ã«æå®ããå¿
è¦ãããã®ã§ãã«ã¹ã¿ãã¤ãºãããã³ã³ããã¼ã©ã¼ã ãæå®ãã¦ãã
# config/routes.rb # å©ç¨ããã¢ã¸ã¥ã¼ã«ã®ã³ã³ããã¼ã©ã¼ãæå®ãã # ä»åã¯ããã©ã«ãã§æå¹ãªpasswordsãregistrationsãsessionsã®3ã¤ãæå® devise_for :users, controllers: { passwords: 'users/passwords', registrations: 'users/registrations', sessions: 'users/sessions', # confirmations: 'users/confirmations', # unlocks: 'users/unlocks', # omniauth_callbacks: 'users/omniauth_callbacks', }
$ rails routes Prefix Verb URI Pattern Controller#Action new_user_session GET /users/sign_in(.:format) users/sessions#new user_session POST /users/sign_in(.:format) users/sessions#create destroy_user_session DELETE /users/sign_out(.:format) users/sessions#destroy new_user_password GET /users/password/new(.:format) users/passwords#new edit_user_password GET /users/password/edit(.:format) users/passwords#edit user_password PATCH /users/password(.:format) users/passwords#update PUT /users/password(.:format) users/passwords#update POST /users/password(.:format) users/passwords#create cancel_user_registration GET /users/cancel(.:format) users/registrations#cancel new_user_registration GET /users/sign_up(.:format) users/registrations#new edit_user_registration GET /users/edit(.:format) users/registrations#edit user_registration PATCH /users(.:format) users/registrations#update PUT /users(.:format) users/registrations#update DELETE /users(.:format) users/registrations#destroy POST /users(.:format) users/registrations#create
ð± ãã¨ã¯çæããã³ã³ããã¼ã©ã¼ã好ããªããã«ã«ã¹ã¿ãã¤ãºããã°OKã ãã
# app/controllers/users/sessions_controller.rb # frozen_string_literal: true class Users::SessionsController < Devise::SessionsController # before_action :configure_sign_in_params, only: [:create] # GET /resource/sign_in def new # èªç±ã«ã«ã¹ã¿ãã¤ãºãã # ã³ã¡ã³ãã¢ã¦ããããã¢ã¯ã·ã§ã³ã«ã¤ãã¦ã¯ãDevise::SessionsControllerã®ã¢ã¯ã·ã§ã³ããã®ã¾ã¾ä½¿ãããã®ã§æåã¯å¤ãããªãã logger.debug params super end # POST /resource/sign_in # def create # super # end # DELETE /resource/sign_out # def destroy # super # end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_in_params # devise_parameter_sanitizer.permit(:sign_in, keys: [:attribute]) # end end
ð± super
ã¯è¦ªã¯ã©ã¹ã§ããDevise::SessionsController
ã®ã¡ã½ããå¼ã³åºãã ããsuper
é¨åã®æåãå¤ãããå ´åã¯Devise::SessionsController
ã®ã³ã¼ããè¦ãªããå¤æ´ãã¦ããDevise::SessionsController
ã®ã³ã¼ããè¦ãã«ã¯Deviseæ¬ä½ã®ã³ã¼ããè¦ãå¿
è¦ãããããgemå
ã®app/controllers/devise/
é
ä¸ã«ç½®ããã¦ããããæ¢ãã¦ã¿ã¦ãã
# https://github.com/heartcombo/devise/blob/master/app/controllers/devise/sessions_controller.rb # frozen_string_literal: true class Devise::SessionsController < DeviseController prepend_before_action :require_no_authentication, only: [:new, :create] prepend_before_action :allow_params_authentication!, only: :create prepend_before_action :verify_signed_out_user, only: :destroy prepend_before_action(only: [:create, :destroy]) { request.env["devise.skip_timeout"] = true } # GET /resource/sign_in def new self.resource = resource_class.new(sign_in_params) clean_up_passwords(resource) yield resource if block_given? respond_with(resource, serialize_options(resource)) end # POST /resource/sign_in def create self.resource = warden.authenticate!(auth_options) set_flash_message!(:notice, :signed_in) sign_in(resource_name, resource) yield resource if block_given? respond_with resource, location: after_sign_in_path_for(resource) end # DELETE /resource/sign_out def destroy signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)) set_flash_message! :notice, :signed_out if signed_out yield if block_given? respond_to_on_destroy end protected def sign_in_params devise_parameter_sanitizer.sanitize(:sign_in) end def serialize_options(resource) methods = resource_class.authentication_keys.dup methods = methods.keys if methods.is_a?(Hash) methods << :password if resource.respond_to?(:password) { methods: methods, only: [:password] } end def auth_options { scope: resource_name, recall: "#{controller_path}#new" } end def translation_scope 'devise.sessions' end private # Check if there is no signed in user before doing the sign out. # # If there is no signed in user, it will set the flash message and redirect # to the after_sign_out path. def verify_signed_out_user if all_signed_out? set_flash_message! :notice, :already_signed_out respond_to_on_destroy end end def all_signed_out? users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) } users.all?(&:blank?) end def respond_to_on_destroy # We actually need to hardcode this as Rails default responder doesn't # support returning empty response on GET request respond_to do |format| format.all { head :no_content } format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) } end end end
ð± Devise::SessionsController
ã®ã³ã¼ããã³ããããã°ãã®ã¾ã¾åãã®ã§ã好ããªããã«ã«ã¹ã¿ãã¤ãºãã¦ãã
# app/controllers/users/sessions_controller.rb # frozen_string_literal: true class Users::SessionsController < Devise::SessionsController # before_action :configure_sign_in_params, only: [:create] # GET /resource/sign_in def new self.resource = resource_class.new(sign_in_params) clean_up_passwords(resource) # èªç±ã«ã«ã¹ã¿ãã¤ãºãã logger.debug resource.attributes yield resource if block_given? respond_with(resource, serialize_options(resource)) end # POST /resource/sign_in # def create # super # end # DELETE /resource/sign_out # def destroy # super # end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_in_params # devise_parameter_sanitizer.permit(:sign_in, keys: [:attribute]) # end end
åè
021 Strong Parameterãã«ã¹ã¿ãã¤ãºãã
ð± ãã°ã¤ã³ãã©ã¼ã ããµã¤ã³ã¢ãããã©ã¼ã ã«ããã¹ããã£ã¼ã«ãã追å ãããå ´åããããããã§ãDeviseã§ã¯Strong Parameterã§è¨±å¯ãããå±æ§ãããã©ã«ãã§æ±ºã¾ã£ã¦ããããããã¥ã¼ã ãã§ãªãStrong Parameterãå¤æ´ããå¿ è¦ããããã ã
ð± ããã©ã«ãã§è¨±å¯ããã¦ããå±æ§ã¯ä»¥ä¸ã®éãã ãã
ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | èå¥å | æ¦è¦ | 許å¯ããã¦ããå±æ§ |
---|---|---|---|
devise/sessions#create | :sign_in | ãã°ã¤ã³ | |
devise/registrations#create | :sign_up | ãµã¤ã³ã¢ãã | email, password, pasword_confirmation |
devise/registrations#update | :account_update | ã¦ã¼ã¶ã¼æ´æ° | email, password_confirmation, current_password |
ð± ä¾ãã°ãµã¤ã³ã¢ããç»é¢ã§email
ãpassword
ãpasword_confirmation
ã«å ãã¦ãusername
ãå
¥åããããã¨ããããããªå ´åã¯Strong Parameterã§username
ã追å ã§è¨±å¯ããå¿
è¦ãããã以ä¸ã®ããã«devise_parameter_sanitizer.permit
ãå©ç¨ããã°OKã ãã
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base # devise_controller?ã¯Deviseã³ã³ããã¼ã©ã¼ã®å ´åã ãtrueãè¿ã # ã¤ã¾ãconfigure_permitted_parametersã¯Deviseã³ã³ããã¼ã©ã¼ã®å ´åã ãå®è¡ããã before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters # ãµã¤ã³ã¢ããæã«usernameã追å ã§è¨±å¯ãã devise_parameter_sanitizer.permit(:sign_up, keys: [:username]) end end
ð± devise_parameter_sanitizer
ã®ä½¿ãæ¹ã¯ä»¥ä¸ã®éãã ãã
# keysãªãã·ã§ã³ã使ãã¨ãpermitããå±æ§ã追å ã§ãã # ããã©ã«ãã§permitããã¦ããpassword/password_confirmationã«å ãã¦ãusernameãpermitãã devise_parameter_sanitizer.permit(:sign_up, keys: [:username]) # exceptãªãã·ã§ã³ã使ãã¨ãpermitããªãå±æ§ãæå®ã§ãã # passwordã ãpermitãã devise_parameter_sanitizer.permit(:sign_up, except: [:password_confirmation]) # ãããã¯ã使ãã¨å®å ¨ã«ãªã¼ãã¼ã©ã¤ãã§ãã # email, password, password_confirmationãpermitãã devise_parameter_sanitizer.permit(:sign_up) do |user| user.permit(:email, :password, :password_confirmation) end # accepts_nested_attributes_forãå©ç¨ãã¦ããå ´åã¯ãxxxx_attributesã使ãã¨é¢é£å ã®å±æ§ãpermitã§ãã devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, address_attributes: [:country, :state, :city, :area, :postal_code]])
ð± ãµã¤ã³ã¢ããã¨ã¦ã¼ã¶ã¼æ´æ°ã®2ã¤ã®æåãå¤æ´ãããå ´åã¯ã2ådevise_parameter_sanitizer.permit
ã使ã£ã¦ãã
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters # ãµã¤ã³ã¢ããã¨ã¦ã¼ã¶ã¼æ´æ°ã®2ã¤ã®æåãå¤æ´ devise_parameter_sanitizer.permit(:sign_up, keys: [:username] devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :last_name, :phone, :email, bank_attributes: [:bank_name, :bank_account]]) end end
åè
- GitHub - heartcombo/devise: Flexible authentication solution for Rails with Warden.
- devise/parameter_sanitizer.rb at master · heartcombo/devise · GitHub
- devise - How to specify devise_parameter_sanitizer for edit action? - Stack Overflow
022 ãªãã¤ã¬ã¯ãå ãå¤æ´ãã
ð± ããã©ã«ãã§ã¯ãã°ã¢ã¦ãæã¯root_pathã«ãªãã¤ã¬ã¯ããããããã«ãªã£ã¦ãããApplicationController
ã«after_sign_out_path_for
ã¡ã½ãããå®ç¾©ãã¦pathãè¿ãããã«ããã°ããªãã¤ã¬ã¯ãå
ãå¤æ´ã§ãããã
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base private def after_sign_out_path_for(resource_or_scope) # ããã©ã«ãã¯root_path new_user_session_path end end
ð± ãªãã¤ã¬ã¯ãå
ã®å¤æ´ã«ã¯ä»¥ä¸ã®ã¡ã½ãããå©ç¨ã§ãããã使ãæ¹ã¯after_sign_out_path_for
ã¨åãã ãã
ã¡ã½ããå | æ¦è¦ |
---|---|
after_sign_out_path_for | ãã°ã¢ã¦ãæã®ãªãã¤ã¬ã¯ãå |
after_sign_in_path_for | ãµã¤ã³ã¤ã³æã®ãªãã¤ã¬ã¯ãå |
after_sign_up_path_for | ãµã¤ã³ã¢ããæã®ãªãã¤ã¬ã¯ãå |
after_inactive_sign_up_path_for | ãµã¤ã³ã¢ããæã®ãªãã¤ã¬ã¯ãå ï¼Confirmableã¢ã¸ã¥ã¼ã«å©ç¨æï¼ |
after_update_path_for | ã¦ã¼ã¶ã¼æ´æ°æã®ãªãã¤ã¬ã¯ãå |
after_confirmation_path_for | ã¡ã¼ã«ç¢ºèªæã®ãªãã¤ã¬ã¯ãå |
after_resending_confirmation_instructions_path_for | 確èªã¡ã¼ã«åéä¿¡æã®ãªãã¤ã¬ã¯ãå |
after_omniauth_failure_path_for | Omniauth失ææã®ãªãã¤ã¬ã¯ãå |
after_sending_reset_password_instructions_path_for | ãã¹ã¯ã¼ããªã»ããæã®ãªãã¤ã¬ã¯ãå |
ð± è¤æ°ã¢ãã«å©ç¨ãã¦ããå ´åã¯ãå¼æ°ã®resource_or_scope
ã使ãã¨ãªãã¤ã¬ã¯ãå
ãåå²ããããããã
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base private def after_sign_out_path_for(resource_or_scope) if resource_or_scope == :user new_user_session_path elsif resource_or_scope == :admin new_admin_session_path else root_path end end end
åè
- How To: Change the redirect path after destroying a session i.e. signing out · heartcombo/devise Wiki · GitHub
- devise/helpers.rb at master · heartcombo/devise · GitHub
- devise ã§ã¢ã¯ã·ã§ã³ã®å®äºå¾ã«ç§»åãããã¹ãã«ã¹ã¿ãã¤ãºããã « yukku++
- Deviseã§ãµã¤ã³ã¤ã³/ãµã¤ã³ã¢ã¦ãå¾ã®ãªãã¤ã¬ã¯ãå ãå¤æ´ãã - Qiita
- ãDeviseãã¢ã«ã¦ã³ãç»é²ããã¯ãã¤ã³/ ãã¯ãã¢ã¦ããã¢ã«ã¦ã³ãç·¨éå¾ã®ãªã¿ãã¤ã¬ã¯ãå ã®å¤æ´ - Qiita
第5ç« ã¢ãã«ãã«ã¹ã¿ãã¤ãºãã
023 è¤æ°ã¢ãã«ãå©ç¨ãã
ð± Deviseã§ã¯User以å¤ã®å¥ã®ã¢ãã«ãèªè¨¼å¯¾è±¡ã®ã¢ãã«ã¨ãã¦æ±ããããä»åã¯Userã¨Adminã¨ãã2ã¤ã®ã¢ãã«ã使ã£ã¦ã¿ããããã®2ã¤ã®ã¢ãã«ã¯ã³ã³ããã¼ã©ã¼ã»ãã¥ã¼ã»ã«ã¼ãã£ã³ã°ãå ¨ã¦å¥ç©ã¨ãã¦æ±ããããã
ð± è¨å®ãã¡ã¤ã«ãä½æããã¨ãããããããã
$ rails g devise:install
ð± è¨å®ãã¡ã¤ã«ãå¤æ´ãããã
# config/initializers/devise.rb - # config.scoped_views = false + config.scoped_views = true
ð± Deviseã§ã¯Scopeã¨ããæ©è½ã使ã£ã¦Userã¨Adminã¨ãã2ã¤ã®ã¢ãã«ã使ããããã«ãã¦ããããï¼ActiveRecordã®Scopeã¨ã¯å¥ã®æ©è½ãScopeã«ã¤ãã¦è©³ããç¥ãããå ´å㯠057 Warden ãåç
§ãï¼scoped_views
ãtrue
ã«è¨å®ããã¨ãScopeç¨ã®ãã¥ã¼ãåªå
çã«ä½¿ãããã«ãªã£ã¦ãUserç¨ã®ãã¥ã¼ã¨Adminç¨ã®ãã¥ã¼ãå¥åã«ä½¿ããããã«ãªããã
scoped_viewsãfalseã®å ´åã®ãã¥ã¼ã®åªå é ä½ï¼ããã©ã«ãï¼
- ã¢ããªå
ã®deviseãã¥ã¼ï¼
devise/sessions/new.html.erb
ï¼ - gemå
ã®deviseãã¥ã¼ï¼
devise/sessions/new.html.erb
ï¼
scoped_viewsãtrueã®å ´åã®ãã¥ã¼ã®åªå é ä½
- Scopeç¨ã®ãã¥ã¼ï¼
users/sessions/new.html.erb
ï¼ # ãããåªå çã«ä½¿ãããã«ãã - ã¢ããªå
ã®deviseãã¥ã¼ï¼
devise/sessions/new.html.erb
ï¼ - gemå
ã®deviseãã¥ã¼ï¼
devise/sessions/new.html.erb
ï¼
ð± ããã©ã«ãã§ã¯é«éåã®ããscoped_views
ã¯false
ã«è¨å®ããã¦ããã
ð± 次ã¯Userã¢ãã«ã¨Adminã¢ãã«ãä½æãããã
$ rails g devise User $ rails g devise Admin
ð± Userã¨Adminã®ã³ã³ããã¼ã©ã¼ãä½æãã¦ãã
$ rails g devise:controllers users $ rails g devise:controllers admins
ð± Userã¨Adminã®ãã¥ã¼ãä½æãã¦ãã
$ rails g devise:views users $ rails g devise:views admins
ð± $ rails g devise:views
ã§ã¯ãªãã®ã§æ³¨æãã¦ããScopeæå®ãªãã ã¨devise
ã¨ããåå空éã§ãã¥ã¼ãä½ã£ã¦ãã¾ãããä»åã¯config.scoped_views = true
ã«è¨å®ãã¦ãã¦ãUserã¨Adminã«ããããå¥ã®ãã¥ã¼ãç¨æããã®ã§ãscopeã¾ã§æå®ãã¦ãã
ð± ã«ã¼ãã£ã³ã°ãè¨å®ããããã¾ãã¯ä»ã®ã«ã¼ãã£ã³ã°ã確èªãã¦ãã
# config/routes.rb devise_for :users devise_for :admins
$ rails routes new_admin_session GET /admins/sign_in(.:format) devise/sessions#new admin_session POST /admins/sign_in(.:format) devise/sessions#create destroy_admin_session DELETE /admins/sign_out(.:format) devise/sessions#destroy new_admin_password GET /admins/password/new(.:format) devise/passwords#new edit_admin_password GET /admins/password/edit(.:format) devise/passwords#edit admin_password PATCH /admins/password(.:format) devise/passwords#update PUT /admins/password(.:format) devise/passwords#update POST /admins/password(.:format) devise/passwords#create ancel_admin_registration GET /admins/cancel(.:format) devise/registrations#cancel new_admin_registration GET /admins/sign_up(.:format) devise/registrations#new edit_admin_registration GET /admins/edit(.:format) devise/registrations#edit admin_registration PATCH /admins(.:format) devise/registrations#update PUT /admins(.:format) devise/registrations#update DELETE /admins(.:format) devise/registrations#destroy POST /admins(.:format) devise/registrations#create new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy new_user_password GET /users/password/new(.:format) devise/passwords#new edit_user_password GET /users/password/edit(.:format) devise/passwords#edit user_password PATCH /users/password(.:format) devise/passwords#update PUT /users/password(.:format) devise/passwords#update POST /users/password(.:format) devise/passwords#create cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel new_user_registration GET /users/sign_up(.:format) devise/registrations#new edit_user_registration GET /users/edit(.:format) devise/registrations#edit user_registration PATCH /users(.:format) devise/registrations#update PUT /users(.:format) devise/registrations#update DELETE /users(.:format) devise/registrations#destroy POST /users(.:format) devise/registrations#create
ð± Userã¨Adminãã©ã¡ããdevise
ã¨ããåå空éã®ã³ã³ããã¼ã©ã¼ã使ã£ã¦ãã¾ã£ã¦ããããã³ã³ããã¼ã©ã¼ãããããç¨æãããã®ã§ãUserã¨Adminãããããã®ã³ã³ããã¼ã©ã¼ãå©ç¨ããããã«ä¿®æ£ãããã
# config/routes.rb devise_for :users, controllers: { # Userã®SessionsControllerã«ã¯ãUsers::SessionsControllerãå©ç¨ãããä»ã®ã³ã³ããã¼ã©ã¼ãåãããã«ä¿®æ£ããã sessions: 'users/sessions', passwords: 'users/passwords', registrations: 'users/registrations' } devise_for :admins, controllers: { # Adminã®SessionsControllerã«ã¯ãAdmins::SessionsControllerãå©ç¨ãããä»ã®ã³ã³ããã¼ã©ã¼ãåãããã«ä¿®æ£ããã sessions: 'admins/sessions', passwords: 'admins/passwords', registrations: 'admins/registrations' }
ð± ããã§Userã¨Adminã§å¥åã®ã³ã³ããã¼ã©ã¼ã使ãããã
$ rails routes Prefix Verb URI Pattern Controller#Action new_user_session GET /users/sign_in(.:format) users/sessions#new user_session POST /users/sign_in(.:format) users/sessions#create destroy_user_session DELETE /users/sign_out(.:format) users/sessions#destroy new_user_password GET /users/password/new(.:format) users/passwords#new edit_user_password GET /users/password/edit(.:format) users/passwords#edit user_password PATCH /users/password(.:format) users/passwords#update PUT /users/password(.:format) users/passwords#update POST /users/password(.:format) users/passwords#create cancel_user_registration GET /users/cancel(.:format) users/registrations#cancel new_user_registration GET /users/sign_up(.:format) users/registrations#new edit_user_registration GET /users/edit(.:format) users/registrations#edit user_registration PATCH /users(.:format) users/registrations#update PUT /users(.:format) users/registrations#update DELETE /users(.:format) users/registrations#destroy POST /users(.:format) users/registrations#create new_admin_session GET /admins/sign_in(.:format) admins/sessions#new admin_session POST /admins/sign_in(.:format) admins/sessions#create destroy_admin_session DELETE /admins/sign_out(.:format) admins/sessions#destroy new_admin_password GET /admins/password/new(.:format) admins/passwords#new edit_admin_password GET /admins/password/edit(.:format) admins/passwords#edit admin_password PATCH /admins/password(.:format) admins/passwords#update PUT /admins/password(.:format) admins/passwords#update POST /admins/password(.:format) admins/passwords#create ancel_admin_registration GET /admins/cancel(.:format) admins/registrations#cancel new_admin_registration GET /admins/sign_up(.:format) admins/registrations#new edit_admin_registration GET /admins/edit(.:format) admins/registrations#edit admin_registration PATCH /admins(.:format) admins/registrations#update PUT /admins(.:format) admins/registrations#update DELETE /admins(.:format) admins/registrations#destroy POST /admins(.:format) admins/registrations#create
ð± ããã§å®äºã ããUserç¨ã®ãµã¤ã³ã¢ãããã¼ã¸ã§ãã /users/sign_up
ã¨ã¯å¥ã«ãAdminç¨ã® /admins/sign_up
ã«ã¢ã¯ã»ã¹ã§ããããã«ãªããã
ð± ãã¨è£è¶³ã¨ãã¦ãUserã¨Adminã®sessionã¯å¥ã
ã«ç®¡çããããããcurrent_user
ã¨ã¯å¥ã«Adminç¨ã®current_admin
ãªã©ã®ã¡ã½ãããç¨æããããã
## Userç¨ # ãã°ã¤ã³ä¸ã®userãåå¾ current_user # userãèªè¨¼ authenticate_user! # userããã°ã¤ã³æ¸ã¿ãªãtrue user_signed_in? # userã«ç´ã¥ãsession user_session ## Adminç¨ # ãã°ã¤ã³ä¸ã®adminãåå¾ current_admin # adminãèªè¨¼ authenticate_admin! # adminããã°ã¤ã³æ¸ã¿ãªãtrue admin_signed_in? # adminã«ç´ã¥ãsession admin_session
ð± ã¾ãUserã§ã®ãã°ã¤ã³ç¶æ ã¨Adminã§ã®ãã°ã¤ã³ç¶æ ã¯å¥ã ã«ç®¡çããããããã¢ãã«æ¯ã«ãã°ã¤ã³/ãã°ã¢ã¦ããå¯è½ã ãããã ã以ä¸ã®è¨å®ããããã¨ã§ãã°ã¢ã¦ãæã«å ¨ã¢ãã«ã§ãã°ã¢ã¦ããããããã«ãããã¨ãå¯è½ã ãã
# config/initializers/devise.rb # ãã°ã¢ã¦ãæã«å ¨ã¦ã®Scopeã§ã®ãã°ã¢ã¦ãã¨ããã # falseã®å ´åã¯/users/sign_outã§ãã°ã¢ã¦ãããå ´åãuser Scopeã ãã§ã®ãã°ã¢ã¦ãã«ãªãã config.sign_out_all_scopes = true
ð± ã¡ãã»ã¼ã¸ãã¢ãã«æ¯ã«æå®å¯è½ã ãã
# config/locales/devise.en.yml # åç §: https://github.com/heartcombo/devise/wiki/How-to-Setup-Multiple-Devise-User-Models#8-setting-custom-flash-messages-per-resource en: devise: confirmations: # Userç¨ã®æè¨ confirmed: "Your email address has been successfully confirmed." # Adminç¨ã®æè¨ admin_user: confirmed: "Your admin email address has been successfully confirmed."
åè
- How to Setup Multiple Devise User Models · heartcombo/devise Wiki · GitHub
- Railsã§deviseã²ã¨ã¤ã§è¤æ°ã¢ãã«ã管çããã - Qiita
024 emailã®ä»£ããã«usernameã§ãã°ã¤ã³ããã
ð¦ð» ããã©ã«ãã§ã¯ãã°ã¤ã³ããéã«ã¯email
ã¨password
ãå
¥åããããã
ð¦ð» email
ã®ä»£ããã«username
ã使ã£ã¦ãã°ã¤ã³ãã¦ãããã«ã¯ã©ãããã°ããããªï¼
ð± ã¾ãã¯usersãã¼ãã«ã«username
ã«ã©ã ã追å ãã¦ããusername
ã«ã©ã ã¯email
ã®ä»£ããã«èªè¨¼ã®ãã¼ã«ãªãã®ã§ãuniqueã¤ã³ããã¯ã¹ãç¨æãã¦ä¸æã«ãªãããã«ãã¦ããï¼email
ãããã ã£ãããã«ï¼
$ rails g migration add_username_to_users username:string:uniq invoke active_record create db/migrate/20201114030246_add_username_to_users.rb
ð± ãã¤ã°ã¬ã¼ã·ã§ã³ãã¡ã¤ã«ã¯ãããªæãã ãã
# db/migrate/20201114030246_add_username_to_users.rb class AddUsernameToUsers < ActiveRecord::Migration[6.0] def change add_column :users, :username, :string add_index :users, :username, unique: true end end
$ rails db:migrate
ð± usernameã®ããªãã¼ã·ã§ã³ãè¨å®ãã¦ãã
# app/models/user.rb validates :username, uniqueness: true, presence: true
ð± è¨å®ãã¡ã¤ã«ã§èªè¨¼ãã¼ãemail
ããusername
ã«å¤æ´ãããã
# config/initializers/devise.rb - # config.authentication_keys = [:email] + config.authentication_keys = [:username]
ð± ãµã¤ã³ã¢ããç»é¢ã§username
ãå
¥åã§ããããã«ä¿®æ£ãããã
# app/views/devise/registrations/new.html.erb <h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <!-- usernameã®å ¥åæ¬ã追å --> + <div class="field"> + <%= f.label :username %><br /> + <%= f.text_field :username, autocomplete: "username" %> + </div> <div class="field"> <%= f.label :password %> <% if @minimum_password_length %> <em>(<%= @minimum_password_length %> characters minimum)</em> <% end %><br /> <%= f.password_field :password, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %>
ð± ç»é¢ã¯ãããªæãã«ãªããã
ð± Strong Parameterãè¨å®ãããããã®ã¾ã¾ã ã¨èªè¨¼ãã¼ã§ãªãemail
å±æ§ã¯è¨±å¯ãããªãã®ã§ã許å¯ããããã«ä¿®æ£ããããStrong Parameterã«ã¹ã¿ãã¤ãºã«ã¤ãã¦è©³ããç¥ãããå ´å㯠021 Strong Parameterãã«ã¹ã¿ãã¤ãºãã ã確èªãã¦ãã
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters # ãµã¤ã³ã¢ããæã«emailå±æ§ã許å¯ãã devise_parameter_sanitizer.permit(:sign_up, keys: [:email]) end end
ð± ããã¾ã§ã§ãµã¤ã³ã¢ãããã§ããããã«ãªã£ããã次ã¯username
ã§ãã°ã¤ã³ã§ããããã«ããããã«ããã°ã¤ã³ç»é¢ã§email
ã®ä»£ããã«username
ã使ãããã«ä¿®æ£ãããã
# app/views/devise/sessions/new.html.erb <h2>Log in</h2> <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> <!-- emailã®ä»£ããã«usernameã使ã --> - <div class="field"> - <%= f.label :email %><br /> - <%= f.email_field :email, autofocus: true, autocomplete: "email" %> - </div> + <div class="field"> + <%= f.label :username %><br /> + <%= f.text_field :username, autofocus: true, autocomplete: "username" %> + </div> <div class="field"> <%= f.label :password %><br /> <%= f.password_field :password, autocomplete: "current-password" %> </div> <% if devise_mapping.rememberable? %> <div class="field"> <%= f.check_box :remember_me %> <%= f.label :remember_me %> </div> <% end %> <div class="actions"> <%= f.submit "Log in" %> </div> <% end %> <%= render "users/shared/links" %>
ð± ããã§username
ã§ãã°ã¤ã³ã§ããããã«ãªã£ããã
åè
- How To: Allow users to sign in with something other than their email address · heartcombo/devise Wiki · GitHub
- [Rails]ã¡ã¼ã«ã¢ãã¬ã¹ä»¥å¤ã§ãµã¤ã³ã¤ã³ã§ããããã«ãã[devise] ï½ ããµããµæè¡é¨
第6ç« ã«ã¼ãã£ã³ã°ãã«ã¹ã¿ãã¤ãºãã
025 deivse_forã§ã«ã¼ãã£ã³ã°ãå®ç¾©ãã
ð± routes.rbã§devise_for
ã¡ã½ãããå©ç¨ããã¨ãã¢ã¸ã¥ã¼ã«ã«å¯¾å¿ããã«ã¼ãã£ã³ã°ãèªåã§å®ç¾©ãããããä¾ãã°Database Authenticatableã¢ã¸ã¥ã¼ã«ã ããæå¹ã«ããå ´åãDatabase Authenticatableã¢ã¸ã¥ã¼ã«ã®ã«ã¼ãã£ã³ã°ã ããdevise_for
ã«ãã£ã¦å®ç¾©ããããã
# app/models/user.rb class User < ApplicationRecord devise :database_authenticatable end
# config/routes.rb Rails.application.routes.draw do devise_for :users end
$ rails routes Prefix Verb URI Pattern Controller#Action new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
ð± ããã©ã«ãã§æå¹ã«ãªã£ã¦ãã5ã¤ã®ã¢ã¸ã¥ã¼ã«ã使ãå ´åã¯ãã³ã³ããã¼ã©ã¼ãåå¨ããDatabase Authenticatableã¢ã¸ã¥ã¼ã«ã»Recoverableã¢ã¸ã¥ã¼ã«ã»Registerableã¢ã¸ã¥ã¼ã«ã«å¯¾å¿ããã«ã¼ãã£ã³ã°ãdevise_forã«ãã£ã¦å®ç¾©ããããã
# config/routes.rb Rails.application.routes.draw do devise_for :users end
# app/models/user.rb class User < ApplicationRecord devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable end
$ rails routes Prefix Verb URI Pattern Controller#Action new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy new_user_password GET /users/password/new(.:format) devise/passwords#new edit_user_password GET /users/password/edit(.:format) devise/passwords#edit user_password PATCH /users/password(.:format) devise/passwords#update PUT /users/password(.:format) devise/passwords#update POST /users/password(.:format) devise/passwords#create cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel new_user_registration GET /users/sign_up(.:format) devise/registrations#new edit_user_registration GET /users/edit(.:format) devise/registrations#edit user_registration PATCH /users(.:format) devise/registrations#update PUT /users(.:format) devise/registrations#update DELETE /users(.:format) devise/registrations#destroy POST /users(.:format) devise/registrations#create
ð± æå¹ãªã¢ã¸ã¥ã¼ã«ã«ãã£ã¦èªåã§ã«ã¼ãã£ã³ã°ãå¤ããã®ã§æ³¨æãã¦ãã
026 devise_forãã«ã¹ã¿ãã¤ãºãã
ð± devise_for
ã«ã¯ããããªãªãã·ã§ã³ãç¨æããã¦ããããããã®ãªãã·ã§ã³ãæå®ãããã¨ã§ã«ã¼ãã£ã³ã°ãã«ã¹ã¿ãã¤ãºã§ãããã
ð± devise_forã®ãªãã·ã§ã³ã¯ä»¥ä¸ã®éãã ãã
ãªãã·ã§ã³ | æ¦è¦ | å©ç¨ä¾ |
---|---|---|
controllers | ã³ã³ããã¼ã©ã¼å¤æ´ ã«ã¹ã¿ã ã³ã³ããã¼ã©ã¼ãå©ç¨ããéã«æå®ãã |
# devise/sessions -> users/sessions devise_for :users, controllers: { sessions: "users/sessions" } |
path | /users/sign_in ã®users é¨åã®pathå¤æ´ |
# /users/sign_in -> /accounts/sing_in devise_for :users, path: 'accounts' |
path_names | /users/sign_in ã®sign_in é¨åã®pathå¤æ´ |
# /users/sign_in -> /users/login # /users/sign_out -> /users/logout devise_for :users, path_names: { sign_in: "login", sign_out: "logout" } |
sign_out_via | sign_outæã®HTTPã¡ã½ãã | # [:post, :delete]ã®ã¿ã«å¤æ´ # ããã©ã«ã: :delete devise_for :users, sign_out_via: [:post, :delete] |
only | æå®ã³ã³ããã¼ã©ã¼ã ãæå¹ | devise_for :users, only: :sessions |
skip | æå®ã³ã³ããã¼ã©ã¼ã¯ç¡å¹ | devise_for :users, skip: :sessions |
class_name | ã¢ãã«æå® | devise_for :users, class_name: 'Account' |
singular | Userã®åæ°å½¢(ãã«ãã¼ã«å½±é¿) | # ãã®å ´åãcurrent_admin ã¯current_manager ã«ãªãdevise_for :admins, singular: :manager |
skip_helpers | URLãã«ãã¼ãä½ããªã æ¢åã³ã¼ãã¨ã®ã³ã³ããªã¯ããé¿ãããå ´åã«ä½¿ã |
# ããã©ã«ã: false devise_for :users, skip: [:registrations, :confirmations], skip_helpers: true devise_for :users, skip_helpers: [:registrations, :confirmations] |
format | (.:format) ãã¤ãã |
# ããã©ã«ã: true devise_for :users, format: false |
module | ã³ã³ããã¼ã©ã¼ã®åå空éå¤æ´ | # ããã©ã«ã: "devise" # Devise::SessionsController -> Users::SessionsController devise_for :users, module: "users" |
failure_app | èªè¨¼å¤±ææã®Rackã¢ããª(wardenã®ã¬ã·ãåç §) | |
constraints | ã«ã¼ãã£ã³ã°æç´ | |
defaults | ãã©ã¡ã¼ã¿ã¼ã®ããã©ã«ãå¤ |
åè
027 åå空éãæå®ãã
ð± devise_for
ã¡ã½ããã¯namespace
ã¡ã½ãããªã©ã®Railsã®æ¢åã®ã¡ã½ããã¨çµã¿åããã¦ä½¿ããããnamespace
ã使ãã¨åå空éãæå®ã§ãããã
# config/routes.rb namespace :hoge do devise_for :users end
$ rails routes Prefix Verb URI Pattern Controller#Action new_hoge_user_session GET /hoge/users/sign_in(.:format) hoge/sessions#new hoge_user_session POST /hoge/users/sign_in(.:format) hoge/sessions#create destroy_hoge_user_session DELETE /hoge/users/sign_out(.:format) hoge/sessions#destroy new_hoge_user_password GET /hoge/users/password/new(.:format) hoge/passwords#new edit_hoge_user_password GET /hoge/users/password/edit(.:format) hoge/passwords#edit hoge_user_password PATCH /hoge/users/password(.:format) hoge/passwords#update PUT /hoge/users/password(.:format) hoge/passwords#update POST /hoge/users/password(.:format) hoge/passwords#create cancel_hoge_user_registration GET /hoge/users/cancel(.:format) hoge/registrations#cancel new_hoge_user_registration GET /hoge/users/sign_up(.:format) hoge/registrations#new edit_hoge_user_registration GET /hoge/users/edit(.:format) hoge/registrations#edit hoge_user_registration PATCH /hoge/users(.:format) hoge/registrations#update PUT /hoge/users(.:format) hoge/registrations#update DELETE /hoge/users(.:format) hoge/registrations#destroy POST /hoge/users(.:format) hoge/registrations#create
028 ç¬èªã®ã«ã¼ãã£ã³ã°ãå®ç¾©ãã
ð¦ð» ãµã¤ã³ã¤ã³ç»é¢ã«/sign_in
ã§ã¢ã¯ã»ã¹ãããã¦ãããªã«ã¼ãã£ã³ã°ãå®ç¾©ãããã©ã¨ã©ã¼ã«ãªããããªãã§ï¼
# config/routes.rb get "sign_in", to: "devise/sessions#new"
ð± Deviseã®ã³ã³ããã¼ã©ã¼ã«å¯¾ãã¦ç´ æ´ã«ã«ã¼ãã£ã³ã°ãå®ç¾©ããã¨ã¨ã©ã¼ã«ãªã£ã¡ããããç¬èªã®ã«ã¼ãã£ã³ã°ãå®ç¾©ããã«ã¯ãdevise_scope
ã¨ããã¡ã½ããã使ã£ã¦Scopeãæ示ããå¿
è¦ããããã ã
# config/routes.rb # devise_scopeã使ãuser Scopeã«å¯¾ããã«ã¼ãã£ã³ã°ã§ãããã¨ãæ示ãã # `users`ã§ã¯ãªã`user`ã¨åæ°å½¢ã«ãªãã®ã§æ³¨æ devise_scope :user do get "sign_in", to: "devise/sessions#new" end
ð± devise_for
ã®path
ãªãã·ã§ã³ãpath_names
ãªãã·ã§ã³ãDeviseã®ã«ã¼ãã£ã³ã°ãå¤æ´ããã®ã«å¯¾ãã¦ãdevise_scope
ã¯æ°ããã«ã¼ãã£ã³ã°ã追å ããæãã ãã
ð± ã¡ãªã¿ã«devise_scope
ã«ã¯as
ã¨ããaliasãåå¨ãããããã£ã¡ã使ã£ã¦ãOKã ãã
# config/routes.rb as :user do get "sign_in", to: "devise/sessions#new" end
åè
029 Deviseã®ã«ã¼ãã£ã³ã°ã0ããå®ç¾©ãã
ð¦ð» Deviseã³ã³ããã¼ã©ã¼ã«å¯¾ãã¦ããã©ã«ãã®ã«ã¼ãã£ã³ã°ãå ¨é¨ãªãã«ãã¦ã0ããèªåã§ã«ã¼ãã£ã³ã°ãå®ç¾©ããã«ã¯ã©ãããã°ããï¼
ð± devise_for
ã§ããã©ã«ãã®ã«ã¼ãã£ã³ã°ãå
¨é¨skipãã¦ãdevise_scope
ã§å¥½ããªããã«ã«ã¼ãã£ã³ã°ãå®ç¾©ãã¦ããã°OKã ã
# config/routes.rb # ããã©ã«ãã§å®ç¾©ãããã«ã¼ãã£ã³ã°ã¯å ¨é¨ç¡å¹ã«ãã # `:all`ã¯å ¨ã¦ã®ã³ã³ããã¼ã©ã¼ãæã devise_for :users, skip: :all # ãã¨ã¯ãã®ä¸ã«å¥½ããªããã«ã«ã¼ãã£ã³ã°ãå®ç¾©ãã¦ããã°OK devise_scope :user do get "sign_in", to: "devise/sessions#new" end
ð± ããã©ã«ãã®ã«ã¼ãã£ã³ã°ã¯ãªããªããèªåã§å®ç¾©ããã«ã¼ãã£ã³ã°ã ãã«ãªããã
$ rails routes Prefix Verb URI Pattern Controller#Action sign_in GET /sign_in(.:format) devise/sessions#new
ð± pathã ãã§ãªãuser_session_path
ãªã©ã®URLãã«ãã¼ãå¤ããã®ã§æ³¨æãã¦ãã
åè
030 ãã°ã¤ã³å¾ã¨ãã°ã¤ã³åã§rootã®ã«ã¼ãã£ã³ã°ãåãã
ð± ãã°ã¤ã³å¾ã¨ãã°ã¤ã³åã§rootã®ã«ã¼ãã£ã³ã°ãåãããå ´åã¯ãroutes.rbã§authenticated
ã使ãã°OKã ãã
# config/routes.rb # ãã°ã¤ã³å¾ã®rootã # `authenticated`ãããã¯å ã¯ãã°ã¤ã³å¾ã®ã¦ã¼ã¶ã¼ã«å¯¾ãã¦ã ããããããã # ã©ã¡ããURLãã«ãã¼ã`root_path`ã«ãªãã®ã§ã`as`ãªãã·ã§ã³ã使ã£ã¦å¤æ´ãã¦ããã¦ãããããªãã¨ã¨ã©ã¼ã«ãªããã # ã«ã¼ãã£ã³ã°ã¯ä¸ããé ã«è©ä¾¡ãããã®ã§ããã¡ããä¸ã«ãã¦ãã authenticated do root to: 'dashboard#show', as: :authenticated_root end # ãã°ã¤ã³åã®rootã root to: 'landing#show'
ð± å
é¨çã«ã¯Railsã®constraints
ãå©ç¨ãã¦ããã®ã§ãã³ã³ããã¼ã©ã¼ã§åå²ãããããã¹ãã¼ãã«ãªããã
ð± Scopeãæå®ãããã¨ãå¯è½ã ãã
# config/routes.rb authenticated :admin do root to: 'admin/dashboard#show', as: :admin_root end root to: 'landing#show'
ð± user.roleãæå®ãããã¨ãå¯è½ã ãã
# config/routes.rb authenticated :user, lambda {|user| user.role == "admin"} do root to: "admin/dashboard#show", as: :user_root end root to: 'landing#show'
031 ãã°ã¤ã³å¾ã®ã¿ã¢ã¯ã»ã¹ã§ããã«ã¼ãã£ã³ã°ãå®ç¾©ãã
ð± ãã°ã¤ã³å¾ã®ã¿ã¢ã¯ã»ã¹ã§ããã«ã¼ãã£ã³ã°ãå®ç¾©ããã«ã¯authenticate
ã¡ã½ããã使ã£ã¦ãã
# config/routes.rb # catsãªã½ã¼ã¹ã«ã¯ãã°ã¤ã³å¾ã§ãªãã¨ã¢ã¯ã»ã¹ã§ããªãã # ãã°ã¤ã³åã«ã¢ã¯ã»ã¹ããã¨root_pathã«ãªãã¤ã¬ã¯ããããã authenticate do resources :cats end
ð± ã³ã³ããã¼ã©ã¼ã§authenticate_user!
ã使ãã®ã¨åãæãã ãã
# app/controllers/cats_controller.rb class CatsController < ApplicationController before_action :authenticate_user! end
ð± authenticated
ã¯ãã°ã¤ã³åã ã¨ã«ã¼ãã£ã³ã°ã«matchããªãã®ã«å¯¾ãã¦ãauthenticate
ã¯ãã°ã¤ã³åã ã¨matchããä¸ã§root_pathã«ãªãã¤ã¬ã¯ãããããå°ãéãã®ã§æ³¨æãã¦ãã
032 /users/sign_inã/users/loginã«å¤æ´ãã
ð¦ð» ãã°ã¤ã³ç»é¢ã®pathã/users/sign_in
ãã/users/login
ã«å¤ãããã®ã ãã©
ð± ãããªå ´åã¯devise_for
ã§èªåã§ä½æãããã«ã¼ãã£ã³ã°ãã¹ããããã¦ã代ããã«èªåã§ã«ã¼ãã£ã³ã°ãå®ç¾©ããã¨ãããã
# devise_forã§èªåä½æããã以ä¸ã®3ã¤ã®ã«ã¼ãã£ã³ã°ãã¹ããã # GET /users/sign_in devise/sessions#new # POST /users/sign_in devise/sessions#create # DELETE /users/sign_out devise/sessions#destroy devise_for :users, skip: [:sessions] # 代ããã«ä»¥ä¸ã®3ã¤ã®ã«ã¼ãã£ã³ã°ãèªåã§å®ç¾©ãã # GET /users/login devise/sessions#new # POST /users/login devise/sessions#create # DELETE /users/logout devise/sessions#destroy devise_scope :user do get 'login' => 'devise/sessions#new', as: :new_user_session post 'login' => 'devise/sessions#create', as: :user_session get 'logout' => 'devise/sessions#destroy', as: :destroy_user_session end
ð± å¥ã®ããæ¹ã¨ãã¦ã¯ãdevise_for
ã®path_names
ãªãã·ã§ã³ã使ãæ¹æ³ããããã
devise_for :users, path: '', path_names: { sign_in: 'login', sign_out: 'logout'}
åè
- How To: Change the default sign_in and sign_out routes · heartcombo/devise Wiki · GitHub
- devise ã§ãã°ã¤ã³ãã°ã¢ã¦ãã®ãã¹ãå¤æ´ãããã¨ãã®æ³¨æç¹ - ããããwebãµã¼ãã¹éçºæ¥è¨
第7ç« ã¡ã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºãã
033 ã¡ã¼ã«å 容ãå¤æ´ãã
ð± ã¡ã¼ã«å 容ãã«ã¹ã¿ãã¤ãºããã«ã¯ã¡ã¼ã©ã¼ã®ãã¥ã¼ãå¤æ´ããã°OKã ãã 014 ãã¥ã¼ãã«ã¹ã¿ãã¤ãºãã ã¨ããæ¹ã¯åãã ãã
ð± ã¾ãã¯èªåã®ã¢ããªã«ãã¥ã¼ãã¡ã¤ã«ãã³ãã¼ãã¦ãã
$ rails g devise:views invoke Devise::Generators::SharedViewsGenerator exist app/views/devise/shared create app/views/devise/shared/_error_messages.html.erb create app/views/devise/shared/_links.html.erb invoke form_for exist app/views/devise/confirmations create app/views/devise/confirmations/new.html.erb exist app/views/devise/passwords create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb exist app/views/devise/registrations create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb exist app/views/devise/sessions create app/views/devise/sessions/new.html.erb exist app/views/devise/unlocks create app/views/devise/unlocks/new.html.erb invoke erb exist app/views/devise/mailer create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/email_changed.html.erb create app/views/devise/mailer/password_change.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erb
ð± ãã¨ã¯ä½æãããã¡ã¼ã©ã¼ã®ãã¥ã¼ãã¡ã¤ã«ãèªåã§ä¿®æ£ãã¦ããã°OKã ãã
ð± ã¡ã¼ã©ã¼ã®ãã¥ã¼ãã¡ã¤ã«ã¯ä»¥ä¸ã®5ã¤ã ãã
ãã¥ã¼ãã¡ã¤ã« | æ¦è¦ | ã¢ã¸ã¥ã¼ã« |
---|---|---|
app/views/devise/mailer/confirmation_instructions.html.erb | confirmationã®æ示ã¡ã¼ã« | Confirmable |
app/views/devise/mailer/email_changed.html.erb | ã¡ã¼ã«ã¢ãã¬ã¹å¤æ´ã¡ã¼ã« | Database Authenticatable |
app/views/devise/mailer/password_change.html.erb | ãã¹ã¯ã¼ãå¤æ´ã¡ã¼ã« | Database Authenticatable |
app/views/devise/mailer/reset_password_instructions.html.erb | ãã¹ã¯ã¼ããªã»ããã®æ示ã¡ã¼ã« | Recoverable |
app/views/devise/mailer/unlock_instructions.html.erb | ã¢ã³ããã¯ã®æ示ã¡ã¼ã« | Lockable |
034 ã¡ã¼ã«ã®fromæ¬ãå¤æ´ãã
ð± Deviseã§éä¿¡ããã¡ã¼ã«ã®fromæ¬ãå¤æ´ããã«ã¯config.mailer_sender
ãè¨å®ãã¦ãã
# config/initializers/devise.rb - config.mailer_sender = '[email protected]' + config.mailer_sender = '[email protected]'
035 ã¡ã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºãã
ð± ã¡ã¼ã©ã¼èªä½ãã«ã¹ã¿ãã¤ãºãããå ´åã¯Devise::Mailer
ãç¶æ¿ããã¡ã¼ã©ã¼ã¯ã©ã¹ãä½æãããã
# app/mailers/my_mailer.rb class MyMailer < Devise::Mailer # application_helperã®ãã«ãã¼ã使ããããã«ãã helper :application # URLãã«ãã¼ã使ããããã«ãã include Devise::Controllers::UrlHelpers # my_mailerã§ã¯ãªãdevise/mailerã®ãã¥ã¼ã使ãããã«ãã default template_path: 'devise/mailer' end
ð± ä½æããã¡ã¼ã©ã¼ã¯ã©ã¹ãDeviseã®ã¡ã¼ã©ã¼ã¨ãã¦è¨å®ããããå ¨ã¦ã®ã¢ã¸ã¥ã¼ã«ã§ãã®ã¡ã¼ã©ã¼ã使ããããã«ãªããã
# config/initializers/devise.rb config.mailer = "MyMailer"
ð± ãã¨ã¯ãããªæãã§ã«ã¹ã¿ãã¤ãºãããã¡ã¼ã«ããªã¼ãã¼ã©ã¤ããã¦ãã
# app/mailers/my_mailer.rb class MyMailer < Devise::Mailer # ...çç¥... # Confirmableã¢ã¸ã¥ã¼ã«ã®confirmationæ示ã®ã¡ã¼ã« # # å¼æ° # record: user # token: ãã¼ã¯ã³ # opts: 追å ãªãã·ã§ã³ä»ãã®hash def confirmation_instructions(record, token, opts={}) # ãããã¼è¿½å headers["Custom-header"] = "Bar" # å¼æ°ã®optsãå©ç¨ããã¨fromãªã©ã®ãããã¼ããªã¼ãã¼ã©ã¤ãã§ãã opts[:from] = '[email protected]' opts[:reply_to] = '[email protected]' # å ã®å¦çããã®ã¾ã¾å®è¡ super end end
ð± Devise::Mailer
èªä½ã¯ https://github.com/heartcombo/devise/blob/master/app/mailers/devise/mailer.rb ã«å®ç¾©ããã¦ããã
# frozen_string_literal: true if defined?(ActionMailer) class Devise::Mailer < Devise.parent_mailer.constantize include Devise::Mailers::Helpers def confirmation_instructions(record, token, opts = {}) @token = token devise_mail(record, :confirmation_instructions, opts) end def reset_password_instructions(record, token, opts = {}) @token = token devise_mail(record, :reset_password_instructions, opts) end def unlock_instructions(record, token, opts = {}) @token = token devise_mail(record, :unlock_instructions, opts) end def email_changed(record, opts = {}) devise_mail(record, :email_changed, opts) end def password_change(record, opts = {}) devise_mail(record, :password_change, opts) end end end
ð± ã¡ã¼ã©ã¼ã®ã¡ã½ããã¯ä»¥ä¸ã®éãã ãã
Database Authenticatable
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#email_changed | Eã¡ã¼ã«å¤æ´å®äºã¡ã¼ã«ãEã¡ã¼ã«å¤æ´æã«éä¿¡ããã |
Devise::Mailer#password_change | ãã¹ã¯ã¼ãå¤æ´å®äºã¡ã¼ã«ããã¹ã¯ã¼ãå¤æ´æã«éä¿¡ããã |
Recoverable
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#reset_password_instructions | ãã¹ã¯ã¼ããªã»ããã¡ã¼ã« |
Confirmable
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#confirmation_instructions | confirmæ示ã¡ã¼ã« |
Lockable
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#unlock_instructions | ã¢ã«ã¦ã³ãã¢ã³ããã¯æ示ã¡ã¼ã« |
åè
036 ã¡ã¼ã«éä¿¡ãéåæã«ãã
ð± ActiveJobã使ã£ã¦ããå ´åãDeviseã®ã¡ã¼ã«éä¿¡ãActiveJobãä»ãã¦è¡ãããããã©ã«ãã§ã¯Deviseã®ã¡ã¼ã«éä¿¡ã¯åæéä¿¡ã«ãªã£ã¦ããã
# https://github.com/heartcombo/devise/blob/45b831c4ea5a35914037bd27fe88b76d7b3683a4/lib/devise/models/authenticatable.rb#L200 def send_devise_notification(notification, *args) # mailãç¨æ message = devise_mailer.send(notification, self, *args) # mailãåæéä¿¡ # Remove once we move to Rails 4.2+ only. if message.respond_to?(:deliver_now) message.deliver_now else message.deliver end end
ð± ã¡ã¼ã«éä¿¡ãéåæã«ããã«ã¯ãUserã¢ãã«ã§send_devise_notification
ããªã¼ãã¼ã©ã¤ããã¦ãããã°OKã ãã
# app/models/user.rb def send_devise_notification(notification, *args) # deliver_laterã使ã£ã¦éåæéä¿¡ããããã«ä¿®æ£ devise_mailer.send(notification, self, *args).deliver_later end
åè
- devise/authenticatable.rb at 45b831c4ea5a35914037bd27fe88b76d7b3683a4 · heartcombo/devise · GitHub
- Active Job with Rails 4 and Devise - Stack Overflow
第8ç« I18nãã«ã¹ã¿ãã¤ãºãã
037 ã¡ãã»ã¼ã¸ãå¤æ´ãã
ð± Deviseã§ã¯flashã¡ãã»ã¼ã¸ãããªãã¼ã·ã§ã³ã¨ã©ã¼ãã¡ã¼ã«ã®ä»¶åã«I18nãå©ç¨ãã¦ããããdevise.en.yml
ã®å¤ãå¤æ´ãããã¨ã§ã対å¿ããã¡ãã»ã¼ã¸ãå¤æ´ã§ãããã
ð± devise.en.yml
ã¯ãããªæãã ãã
# config/locales/devise.en.yml # Additional translations at https://github.com/heartcombo/devise/wiki/I18n en: devise: confirmations: confirmed: "Your email address has been successfully confirmed." send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes." send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes." failure: already_authenticated: "You are already signed in." inactive: "Your account is not activated yet." invalid: "Invalid %{authentication_keys} or password." locked: "Your account is locked." last_attempt: "You have one more attempt before your account is locked." not_found_in_database: "Invalid %{authentication_keys} or password." timeout: "Your session expired. Please sign in again to continue." unauthenticated: "You need to sign in or sign up before continuing." unconfirmed: "You have to confirm your email address before continuing." mailer: confirmation_instructions: subject: "Confirmation instructions" reset_password_instructions: subject: "Reset password instructions" unlock_instructions: subject: "Unlock instructions" email_changed: subject: "Email Changed" password_change: subject: "Password Changed" omniauth_callbacks: failure: "Could not authenticate you from %{kind} because \"%{reason}\"." success: "Successfully authenticated from %{kind} account." passwords: no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." updated: "Your password has been changed successfully. You are now signed in." updated_not_active: "Your password has been changed successfully." registrations: destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon." signed_up: "Welcome! You have signed up successfully." signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address." updated: "Your account has been updated successfully." updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again" sessions: signed_in: "Signed in successfully." signed_out: "Signed out successfully." already_signed_out: "Signed out successfully." unlocks: send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes." send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes." unlocked: "Your account has been unlocked successfully. Please sign in to continue." errors: messages: already_confirmed: "was already confirmed, please try signing in" confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" expired: "has expired, please request a new one" not_found: "not found" not_locked: "was not locked" not_saved: one: "1 error prohibited this %{resource} from being saved:" other: "%{count} errors prohibited this %{resource} from being saved:"
ð± ãã®å¤ãå¤æ´ãããã¨ã§Deviseã®ã¡ãã»ã¼ã¸ãå¤æ´ã§ãããã
038 ã¡ãã»ã¼ã¸ãæ¥æ¬èªåãã
ð± ã¡ãã»ã¼ã¸ãæ¥æ¬èªåããã«ã¯ãRailsã®ããã©ã«ããã±ã¼ã«ã:ja
ã«å¤æ´ãã¦ãjaãã±ã¼ã«ãã¡ã¤ã«ãè¨ç½®ããã°OKã ãã
ð± ã¾ãããã©ã«ããã±ã¼ã«ãæ¥æ¬èªã«è¨å®ãã¦ãã
# config/application.rb config.i18n.default_locale = :ja
ð± 次ã«jaãã±ã¼ã«ãã¡ã¤ã«ãè¨ç½®ãããã https://github.com/heartcombo/devise/wiki/I18n#japanese-devisejayml ã«æ¥æ¬èªåããããã±ã¼ã«ãã¡ã¤ã«ãããã®ã§å©ç¨ãã¦ãã
# config/locales/devise.ja.yml # Additional translations at https://github.com/plataformatec/devise/wiki/I18n ja: devise: confirmations: confirmed: "ã¢ã«ã¦ã³ãã®ç¢ºèªãæåãã¾ããã" send_instructions: "ã¢ã«ã¦ã³ãã®ç¢ºèªæ¹æ³ãã¡ã¼ã«ã§ãé£çµ¡ãã¾ãã" send_paranoid_instructions: "ããªãã®ã¡ã¼ã«ã¢ãã¬ã¹ãç»é²æ¸ã¿ã®å ´åãã¢ã«ã¦ã³ãã®ç¢ºèªæ¹æ³ãã¡ã¼ã«ã§ãé£çµ¡ãã¾ãã" failure: already_authenticated: "æ¢ã«ãã°ã¤ã³æ¸ã¿ã§ãã" inactive: 'ã¢ã«ã¦ã³ããæå¹ã«ãªã£ã¦ãã¾ããã' invalid: 'ã¡ã¼ã«ã¢ãã¬ã¹ããã¹ã¯ã¼ããéãã¾ãã' locked: "ã¢ã«ã¦ã³ããããã¯ããã¦ãã¾ãã" last_attempt: "ããä¸åãã°ã¤ã³ã«å¤±æãããã¢ã«ã¦ã³ããããã¯ããã¾ãã" not_found_in_database: "ã¡ã¼ã«ã¢ãã¬ã¹ã¾ãã¯ãã¹ã¯ã¼ããç¡å¹ã§ãã" timeout: "ä¸å®æéãçµéãããããå度ãã°ã¤ã³ãå¿ è¦ã§ã" unauthenticated: "ç¶ããã«ã¯ããã°ã¤ã³ã¾ãã¯ç»é²ï¼ãµã¤ã³ã¢ããï¼ãå¿ è¦ã§ãã" unconfirmed: "ç¶ããåã«ãã¢ã«ã¦ã³ãã®ç¢ºèªããé¡ããã¾ãã" mailer: confirmation_instructions: subject: "ã¢ã«ã¦ã³ãã®ç»é²æ¹æ³" reset_password_instructions: subject: "ãã¹ã¯ã¼ãã®åè¨å®" unlock_instructions: subject: "ã¢ã«ã¦ã³ãã®ããã¯è§£é¤" omniauth_callbacks: failure: "%{kind} ããæ¿èªããã¾ããã§ãããçç±ï¼%{reason}" success: "%{kind} ããæ¿èªããã¾ããã" passwords: no_token: "ãã¹ã¯ã¼ããªã»ããã®ã¡ã¼ã«ä»¥å¤ããã¯ããã®ãã¼ã¸ã«ã¢ã¯ã»ã¹ããäºãã§ãã¾ããããããã¹ã¯ã¼ããªã»ããã®ã¡ã¼ã«ããæ¥ã¦ããå ´åã¯ãæ£ããURLã§ã¢ã¯ã»ã¹ãã¦ãããã¨ã確èªãã¦ä¸ããã" send_instructions: "ãã¹ã¯ã¼ãã®ãªã»ããæ¹æ³ãã¡ã¼ã«ã§ãé£çµ¡ãã¾ãã" send_paranoid_instructions: "ã¡ã¼ã«ã¢ãã¬ã¹ãç»é²æ¸ã¿ã®å ´åããã¹ã¯ã¼ã復æ§ç¨ãã¼ã¸ãã®ãªã³ã¯ãã¡ã¼ã«ã§ãé£çµ¡ãã¾ãã" updated: "ãã¹ã¯ã¼ããå¤æ´ãã¾ããããã°ã¤ã³æ¸ã¿ã§ã" updated_not_active: "ãã¹ã¯ã¼ããå¤æ´ãã¾ããã" registrations: destroyed: "ã¢ã«ã¦ã³ããåé¤ãã¾ããããã²ã¾ãã®ãå©ç¨ããå¾ ã¡ãã¦ããã¾ãï¼" signed_up: "ããããï¼ã¢ã«ã¦ã³ãç»é²ãåãä»ãã¾ããã" signed_up_but_inactive: "ã¢ã«ã¦ã³ãã¯ç»é²ããã¦ãã¾ãããæå¹ã«ãªã£ã¦ããªãããå©ç¨ã§ãã¾ããã" signed_up_but_locked: "ã¢ã«ã¦ã³ãã¯ç»é²ããã¦ãã¾ãããããã¯ããã¦ããããå©ç¨ã§ãã¾ããã" signed_up_but_unconfirmed: "確èªã¡ã¼ã«ããç»é²ããã¡ã¼ã«ã¢ãã¬ã¹å®ã«éä¿¡ãã¾ãããã¡ã¼ã«ã«è¨è¼ããããªã³ã¯ãéãã¦ã¢ã«ã¦ã³ããæå¹ã«ãã¦ä¸ããã" update_needs_confirmation: "ã¢ã«ã¦ã³ãæ å ±ãæ´æ°ããã¾ãããæ°ããã¡ã¼ã«ã¢ãã¬ã¹ã®ç¢ºèªãå¿ è¦ã§ããæ´æ°ç¢ºèªã®ã¡ã¼ã«ãæ°ããã¡ã¼ã«ã¢ãã¬ã¹å®ã«éä¿¡ãã¾ããã®ã§ãã¡ã¼ã«ã確èªãè¨è¼ããããªã³ã¯ãéããæ°ããã¡ã¼ã«ã¢ãã¬ã¹ã®ç¢ºèªããé¡ããã¾ãã" updated: "ã¢ã«ã¦ã³ããæ´æ°ããã¾ããã" sessions: signed_in: "ãã°ã¤ã³ãã¾ããã" signed_out: "ãã°ã¢ã¦ããã¾ããã" unlocks: send_instructions: "ã¢ã«ã¦ã³ãã®ããã¯ã解é¤ããæ¹æ³ãã¡ã¼ã«ã§ãé£çµ¡ãã¾ãã" send_paranoid_instructions: "ã¢ã«ã¦ã³ããåå¨ããå ´åãããã¯ã解é¤ããæ¹æ³ãã¡ã¼ã«ã§ãé£çµ¡ãã¾ãã" unlocked: "ã¢ã«ã¦ã³ãã®ããã¯ã解é¤ããã¾ãããç¶ããã«ã¯ãã°ã¤ã³ãã¦ä¸ããã" errors: messages: already_confirmed: "ã¯æ¢ã«ç»é²æ¸ã¿ã§ãããã°ã¤ã³ãã¦ãã ãã" confirmation_period_expired: "%{period}以å ã«ç¢ºèªããå¿ è¦ãããã¾ãã®ã§ãæ°ãããªã¯ã¨ã¹ããã¦ãã ããã" expired: "æå¹æéåãã§ããæ°ãããªã¯ã¨ã¹ããã¦ãã ããã" not_found: "ã¯è¦ã¤ããã¾ããã§ããã" not_locked: "ããã¯ããã¦ãã¾ããã" not_saved: one: "1ã¤ã®ã¨ã©ã¼ã«ããã%{resource} ãä¿åã§ãã¾ããã§ããï¼" other: "%{count} åã®ã¨ã©ã¼ã« ããã§ããï¼"
ð± ããã§ãã°ã¤ã³æãªã©ã«è¡¨ç¤ºãããã¡ãã»ã¼ã¸ãæ¥æ¬èªåããããã
ð± ãã¥ã¼ã®æè¨ã¯I18nã使ããã«ç´æ¥è±èªã§æ¸ããã¦ãããããæ¥æ¬èªåãããªããããã¥ã¼ãæ¥æ¬èªåãããå ´å㯠039 ãã¥ã¼ãæ¥æ¬èªåãã ãåç §ãã¦ãã
039 ãã¥ã¼ãæ¥æ¬èªåãã
ð± Deviseã§ã¯flashã¡ãã»ã¼ã¸ãããªãã¼ã·ã§ã³ã¨ã©ã¼ãã¡ã¼ã«ã®ä»¶åã«I18nãå©ç¨ãã¦ãããããã¥ã¼ã®æè¨ã¯I18nã使ããã«ç´æ¥è±èªã§æ¸ããã¦ããããã 038 ã¡ãã»ã¼ã¸ãæ¥æ¬èªåãã ã®ããæ¹ã§ã¯æ¥æ¬èªåãããªããã ã
ð± devise-i18n
ã¨ããgemãå©ç¨ããã°ãI18nã«å¯¾å¿ãããã¥ã¼ãä½æã§ãããããã¥ã¼ã®æè¨ãæ¥æ¬èªåã§ããããdevise-i18nã§ã¯ã¡ãã»ã¼ã¸ãä¸ç·ã«æ¥æ¬èªåãããããã 038 ã¡ãã»ã¼ã¸ãæ¥æ¬èªåãã ã®æé ã¯ä¸è¦ã ãããããããæ¥æ¬èªåãã¦ãããã
ð± ã¾ãã¯devise-i18n
ãã¤ã³ã¹ãã¼ã«ãã¦ãã
# Gemfile gem 'devise-i18n'
$ bundle install
ð± ããã©ã«ããã±ã¼ã«ãæ¥æ¬èªã«è¨å®ãããã
# config/application.rb config.i18n.default_locale = :ja
ð± devise-i18nã®ã¸ã§ãã¬ã¼ã¿ã¼ã使ã£ã¦ãI18n対å¿ã®ãã¥ã¼ãä½æããããæ¢ã«$ rails g devise:views
ã§ãã¥ã¼ãä½æãã¦ããå ´åã¯ã³ã³ããªã¯ãããããäºåã«åé¤ãã¦ããã¦ãã
$ rails g devise:i18n:views invoke Devise::I18n::SharedViewsGenerator create app/views/devise/shared create app/views/devise/shared/_error_messages.html.erb create app/views/devise/shared/_links.html.erb invoke Devise::I18n::MailerViewsGenerator create app/views/devise/mailer create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/email_changed.html.erb create app/views/devise/mailer/password_change.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erb invoke i18n:form_for create app/views/devise/confirmations create app/views/devise/confirmations/new.html.erb create app/views/devise/passwords create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb create app/views/devise/registrations create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb create app/views/devise/sessions create app/views/devise/sessions/new.html.erb create app/views/devise/unlocks create app/views/devise/unlocks/new.html.erb
ð± Deviseã®ã¸ã§ãã¬ã¼ã¿ã¼ã§ä½æãããµã¤ã³ã¤ã³ç»é¢ã¨ãdevise-i18nã®ã¸ã§ãã¬ã¼ã¿ã¼ã§ä½æãããµã¤ã³ã¤ã³ç»é¢ã®ã³ã¼ããæ¯ã¹ã¦ã¿ããã
ð± ãã¡ãã¯Deviseã®ã¸ã§ãã¬ã¼ã¿ã¼ã§ä½æãããµã¤ã³ã¤ã³ç»é¢ã
# app/views/devise/sessions/new.html.erb <!-- ãLog inããªã©ã®æè¨ãè±èªã§ç´æ¥æ¸ããã¦ãã --> <h2>Log in</h2> <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <div class="field"> <%= f.label :password %><br /> <%= f.password_field :password, autocomplete: "current-password" %> </div> <% if devise_mapping.rememberable? %> <div class="field"> <%= f.check_box :remember_me %> <%= f.label :remember_me %> </div> <% end %> <div class="actions"> <%= f.submit "Log in" %> </div> <% end %> <%= render "devise/shared/links" %>
ð± ãã¡ãã¯devise-i18nã®ã¸ã§ãã¬ã¼ã¿ã¼ã§ä½æãããµã¤ã³ã¤ã³ç»é¢ããLog inããªã©ã®æè¨ãt
ã¡ã½ãããå©ç¨ãã¦æ¸ããã¦ãããã
# app/views/devise/sessions/new.html.erb <!-- ãLog inããªã©ã®æè¨ã`t`ã¡ã½ãããå©ç¨ãã¦æ¸ããã¦ãã --> <h2><%= t('.sign_in') %></h2> <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <div class="field"> <%= f.label :password %><br /> <%= f.password_field :password, autocomplete: "current-password" %> </div> <% if devise_mapping.rememberable? %> <div class="field"> <%= f.check_box :remember_me %> <%= f.label :remember_me %> </div> <% end %> <div class="actions"> <%= f.submit t('.sign_in') %> </div> <% end %> <%= render "devise/shared/links" %>
ð± æå¾ã«jaãã±ã¼ã«ãã¡ã¤ã«ãä½æãããã
$ rails g devise:i18n:locale ja create config/locales/devise.views.ja.yml
ð± ãã®ãã±ã¼ã«ãã¡ã¤ã«ã¯ãã¥ã¼ã®I18nã ãã§ãªãã¡ãã»ã¼ã¸ã®I18nã«ã対å¿ãã¦ãããããªã®ã§Deviseã®jaãã±ã¼ã«ãã¡ã¤ã«ã¯ããã ãããã°OKã ãã
ja: activerecord: attributes: user: confirmation_sent_at: ãã¹ã¯ã¼ã確èªéä¿¡æå» confirmation_token: ãã¹ã¯ã¼ã確èªç¨ãã¼ã¯ã³ confirmed_at: ãã¹ã¯ã¼ã確èªæå» created_at: ä½ææ¥ current_password: ç¾å¨ã®ãã¹ã¯ã¼ã current_sign_in_at: ç¾å¨ã®ãã°ã¤ã³æå» current_sign_in_ip: ç¾å¨ã®ãã°ã¤ã³IPã¢ãã¬ã¹ email: Eã¡ã¼ã« encrypted_password: æå·åãã¹ã¯ã¼ã failed_attempts: 失æãããã°ã¤ã³è©¦è¡åæ° last_sign_in_at: æçµãã°ã¤ã³æå» last_sign_in_ip: æçµãã°ã¤ã³IPã¢ãã¬ã¹ locked_at: ããã¯æå» password: ãã¹ã¯ã¼ã password_confirmation: ãã¹ã¯ã¼ãï¼ç¢ºèªç¨ï¼ remember_created_at: ãã°ã¤ã³è¨æ¶æå» remember_me: ãã°ã¤ã³ãè¨æ¶ãã reset_password_sent_at: ãã¹ã¯ã¼ããªã»ããéä¿¡æå» reset_password_token: ãã¹ã¯ã¼ããªã»ããç¨ãã¼ã¯ã³ sign_in_count: ãã°ã¤ã³åæ° unconfirmed_email: æªç¢ºèªEã¡ã¼ã« unlock_token: ããã¯è§£é¤ç¨ãã¼ã¯ã³ updated_at: æ´æ°æ¥ models: user: ã¦ã¼ã¶ devise: confirmations: confirmed: ã¡ã¼ã«ã¢ãã¬ã¹ã確èªã§ãã¾ããã new: resend_confirmation_instructions: ã¢ã«ã¦ã³ã確èªã¡ã¼ã«åé send_instructions: ã¢ã«ã¦ã³ãã®æå¹åã«ã¤ãã¦æ°å以å ã«ã¡ã¼ã«ã§ãé£çµ¡ãã¾ãã send_paranoid_instructions: ã¡ã¼ã«ã¢ãã¬ã¹ãç»é²æ¸ã¿ã®å ´åãæ¬äººç¢ºèªç¨ã®ã¡ã¼ã«ãæ°å以å ã«éä¿¡ããã¾ãã failure: already_authenticated: ãã§ã«ãã°ã¤ã³ãã¦ãã¾ãã inactive: ã¢ã«ã¦ã³ããæå¹åããã¦ãã¾ãããã¡ã¼ã«ã«è¨è¼ãããæé ã«ãããã£ã¦ãã¢ã«ã¦ã³ããæå¹åãã¦ãã ããã invalid: "%{authentication_keys}ã¾ãã¯ãã¹ã¯ã¼ããéãã¾ãã" last_attempt: ããä¸å誤ãã¨ã¢ã«ã¦ã³ããããã¯ããã¾ãã locked: ã¢ã«ã¦ã³ãã¯åçµããã¦ãã¾ãã not_found_in_database: "%{authentication_keys}ã¾ãã¯ãã¹ã¯ã¼ããéãã¾ãã" timeout: ã»ãã·ã§ã³ãã¿ã¤ã ã¢ã¦ããã¾ãããããä¸åº¦ãã°ã¤ã³ãã¦ãã ããã unauthenticated: ã¢ã«ã¦ã³ãç»é²ãããã¯ãã°ã¤ã³ãã¦ãã ããã unconfirmed: ã¡ã¼ã«ã¢ãã¬ã¹ã®æ¬äººç¢ºèªãå¿ è¦ã§ãã mailer: confirmation_instructions: action: ã¡ã¼ã«ã¢ãã¬ã¹ã®ç¢ºèª greeting: "%{recipient}æ§" instruction: 以ä¸ã®ãªã³ã¯ãã¯ãªãã¯ããã¡ã¼ã«ã¢ãã¬ã¹ã®ç¢ºèªæç¶ãå®äºããã¦ãã ããã subject: ã¡ã¼ã«ã¢ãã¬ã¹ç¢ºèªã¡ã¼ã« email_changed: greeting: ããã«ã¡ã¯ã%{recipient}æ§ã message: ããªãã®ã¡ã¼ã«å¤æ´ï¼%{email}ï¼ã®ãç¥ãããããã¾ãã subject: ã¡ã¼ã«å¤æ´å®äºã password_change: greeting: "%{recipient}æ§" message: ãã¹ã¯ã¼ããåè¨å®ããããã¨ãéç¥ãã¾ãã subject: ãã¹ã¯ã¼ãã®å¤æ´ã«ã¤ã㦠reset_password_instructions: action: ãã¹ã¯ã¼ãå¤æ´ greeting: "%{recipient}æ§" instruction: ãã¹ã¯ã¼ãåè¨å®ã®ä¾é ¼ãåãããããã¡ã¼ã«ãéä¿¡ãã¦ãã¾ããä¸ã®ãªã³ã¯ãããã¹ã¯ã¼ãã®åè¨å®ãã§ãã¾ãã instruction_2: ãã¹ã¯ã¼ãåè¨å®ã®ä¾é ¼ããã¦ããªãå ´åããã®ã¡ã¼ã«ãç¡è¦ãã¦ãã ããã instruction_3: ãã¹ã¯ã¼ãã®åè¨å®ã¯ãä¸ã®ãªã³ã¯ããæ°ãããã¹ã¯ã¼ããç»é²ããã¾ã§å®äºãã¾ããã subject: ãã¹ã¯ã¼ãã®åè¨å®ã«ã¤ã㦠unlock_instructions: action: ã¢ã«ã¦ã³ãã®ããã¯è§£é¤ greeting: "%{recipient}æ§" instruction: ã¢ã«ã¦ã³ãã®ããã¯ã解é¤ããã«ã¯ä¸ã®ãªã³ã¯ãã¯ãªãã¯ãã¦ãã ããã message: ãã°ã¤ã³å¤±æãç¹°ãè¿ããããããã¢ã«ã¦ã³ãã¯ããã¯ããã¦ãã¾ãã subject: ã¢ã«ã¦ã³ãã®åçµè§£é¤ã«ã¤ã㦠omniauth_callbacks: failure: "%{kind} ã¢ã«ã¦ã³ãã«ããèªè¨¼ã«å¤±æãã¾ãããçç±ï¼ï¼%{reason}ï¼" success: "%{kind} ã¢ã«ã¦ã³ãã«ããèªè¨¼ã«æåãã¾ããã" passwords: edit: change_my_password: ãã¹ã¯ã¼ããå¤æ´ãã change_your_password: ãã¹ã¯ã¼ããå¤æ´ confirm_new_password: 確èªç¨æ°ãããã¹ã¯ã¼ã new_password: æ°ãããã¹ã¯ã¼ã new: forgot_your_password: ãã¹ã¯ã¼ããå¿ãã¾ããã? send_me_reset_password_instructions: ãã¹ã¯ã¼ãã®åè¨å®æ¹æ³ãéä¿¡ãã no_token: ãã®ãã¼ã¸ã«ã¯ã¢ã¯ã»ã¹ã§ãã¾ããããã¹ã¯ã¼ãåè¨å®ã¡ã¼ã«ã®ãªã³ã¯ããã¢ã¯ã»ã¹ãããå ´åã«ã¯ãURL ãã確èªãã ããã send_instructions: ãã¹ã¯ã¼ãã®åè¨å®ã«ã¤ãã¦æ°å以å ã«ã¡ã¼ã«ã§ãé£çµ¡ãããã¾ãã send_paranoid_instructions: ã¡ã¼ã«ã¢ãã¬ã¹ãç»é²æ¸ã¿ã®å ´åããã¹ã¯ã¼ãåè¨å®ç¨ã®ã¡ã¼ã«ãæ°å以å ã«éä¿¡ããã¾ãã updated: ãã¹ã¯ã¼ããæ£ããå¤æ´ããã¾ããã updated_not_active: ãã¹ã¯ã¼ããæ£ããå¤æ´ããã¾ããã registrations: destroyed: ã¢ã«ã¦ã³ããåé¤ãã¾ãããã¾ãã®ãå©ç¨ããå¾ ã¡ãã¦ããã¾ãã edit: are_you_sure: æ¬å½ã«ããããã§ãã? cancel_my_account: ã¢ã«ã¦ã³ãåé¤ currently_waiting_confirmation_for_email: "%{email} ã®ç¢ºèªå¾ ã¡" leave_blank_if_you_don_t_want_to_change_it: 空æ¬ã®ã¾ã¾ãªãå¤æ´ãã¾ãã title: "%{resource}ç·¨é" unhappy: æ°ã«å ¥ãã¾ãã update: æ´æ° we_need_your_current_password_to_confirm_your_changes: å¤æ´ãåæ ããã«ã¯ç¾å¨ã®ãã¹ã¯ã¼ããå ¥åãã¦ãã ãã new: sign_up: ã¢ã«ã¦ã³ãç»é² signed_up: ã¢ã«ã¦ã³ãç»é²ãå®äºãã¾ããã signed_up_but_inactive: ãã°ã¤ã³ããããã«ã¯ãã¢ã«ã¦ã³ããæå¹åãã¦ãã ããã signed_up_but_locked: ã¢ã«ã¦ã³ããåçµããã¦ãããããã°ã¤ã³ã§ãã¾ããã signed_up_but_unconfirmed: æ¬äººç¢ºèªç¨ã®ã¡ã¼ã«ãéä¿¡ãã¾ãããã¡ã¼ã«å ã®ãªã³ã¯ããã¢ã«ã¦ã³ããæå¹åããã¦ãã ããã update_needs_confirmation: ã¢ã«ã¦ã³ãæ å ±ãå¤æ´ãã¾ãããå¤æ´ãããã¡ã¼ã«ã¢ãã¬ã¹ã®æ¬äººç¢ºèªã®ãããæ¬äººç¢ºèªç¨ã¡ã¼ã«ãã確èªå¦çããããªã£ã¦ãã ããã updated: ã¢ã«ã¦ã³ãæ å ±ãå¤æ´ãã¾ããã updated_but_not_signed_in: ããªãã®ã¢ã«ã¦ã³ãã¯æ£å¸¸ã«æ´æ°ããã¾ãããããã¹ã¯ã¼ããå¤æ´ããããããå度ãã°ã¤ã³ãã¦ãã ããã sessions: already_signed_out: æ¢ã«ãã°ã¢ã¦ãæ¸ã¿ã§ãã new: sign_in: ãã°ã¤ã³ signed_in: ãã°ã¤ã³ãã¾ããã signed_out: ãã°ã¢ã¦ããã¾ããã shared: links: back: æ»ã didn_t_receive_confirmation_instructions: ã¢ã«ã¦ã³ã確èªã®ã¡ã¼ã«ãåãåã£ã¦ãã¾ããã? didn_t_receive_unlock_instructions: ã¢ã«ã¦ã³ãã®åçµè§£é¤æ¹æ³ã®ã¡ã¼ã«ãåãåã£ã¦ãã¾ããã? forgot_your_password: ãã¹ã¯ã¼ããå¿ãã¾ããã? sign_in: ãã°ã¤ã³ sign_in_with_provider: "%{provider}ã§ãã°ã¤ã³" sign_up: ã¢ã«ã¦ã³ãç»é² minimum_password_length: "ï¼%{count}å以ä¸ï¼" unlocks: new: resend_unlock_instructions: ã¢ã«ã¦ã³ãã®åçµè§£é¤æ¹æ³ãåéãã send_instructions: ã¢ã«ã¦ã³ãã®åçµè§£é¤æ¹æ³ãæ°å以å ã«ã¡ã¼ã«ã§ãé£çµ¡ãã¾ãã send_paranoid_instructions: ã¢ã«ã¦ã³ããè¦ã¤ãã£ãå ´åãã¢ã«ã¦ã³ãã®åçµè§£é¤æ¹æ³ãæ°å以å ã«ã¡ã¼ã«ã§ãé£çµ¡ãã¾ãã unlocked: ã¢ã«ã¦ã³ããåçµè§£é¤ãã¾ããã errors: messages: already_confirmed: ã¯æ¢ã«ç»é²æ¸ã¿ã§ãããã°ã¤ã³ãã¦ãã ããã confirmation_period_expired: ã®æéãåãã¾ããã%{period} ã¾ã§ã«ç¢ºèªããå¿ è¦ãããã¾ãã æ°ãããªã¯ã¨ã¹ããã¦ãã ããã expired: ã®æå¹æéãåãã¾ãããæ°ãããªã¯ã¨ã¹ããã¦ãã ããã not_found: ã¯è¦ã¤ããã¾ããã§ããã not_locked: ã¯åçµããã¦ãã¾ããã not_saved: one: ã¨ã©ã¼ãçºçãããã %{resource} ã¯ä¿åããã¾ããã§ããã other: "%{count} 件ã®ã¨ã©ã¼ãçºçãããã %{resource} ã¯ä¿åããã¾ããã§ããã"
ð± ããã§ãã¥ã¼ã¨ã¡ãã»ã¼ã¸ãæ¥æ¬èªåã§ãããã
ð± ã¡ãªã¿ã«è¤æ°ã¢ãã«ãå©ç¨ãã¦ãã¦Scope対å¿ã®ãã¥ã¼ï¼usersã¨ãadminã¨ãã®ãã¤ï¼ãå¿ è¦ãªå ´åã¯ãScopeãæå®ããã°OKã ãã
$ rails g devise:i18n:views users $ rails g devise:i18n:views admins
第9ç« è¨å®ãã«ã¹ã¿ãã¤ãºãã
040 è¨å®ãå¤æ´ãã
ð± Deviseã®è¨å®ã¯config/initializers/devise.rb
ã§å¤æ´å¯è½ã ãã
ð± åè¨å®é ç®ã¯æ¥æ¬èªã§èª¬æããã¨ä»¥ä¸ã®ãããªæãã ããã¡ãªã¿ã«ã³ã¡ã³ãã¢ã¦ãããã¦ããå¤ãï¼åºæ¬çã«ã¯ï¼ããã©ã«ãå¤ã«ãªããã
# config/initializers/devise.rb # frozen_string_literal: true Devise.setup do |config| # Deviseã使ç¨ããç§å¯éµã # Deviseã¯ãã®ãã¼ãå©ç¨ãã¦tokenãä½æããï¼confirmation_tokenãreset_password_tokenãunlock_tokenï¼ã # ãã®ãã¼ãå¤æ´ããã¨å ¨ã¦ã®tokenãç¡å¹ã«ãªãã # ããã©ã«ãã§ã¯secret_key_baseãsecret_keyã¨ãã¦å©ç¨ããã # config.secret_key = '48bf747d05636bd17b63751533ac6879106a058e94253754a0bfe552d60ab822ad52c25b322c93b90d7479a91fe28da84ac038f8b295d523a4c2a18c08ed9c42' # ==> Controllerã®è¨å® # Devise::SessionsControllerãªã©ã®Deviseã®åã³ã³ããã¼ã©ã¼ã®è¦ªã¯ã©ã¹ã # config.parent_controller = 'DeviseController' # ==> Mailerã®è¨å® # Mailerã®fromã config.mailer_sender = '[email protected]' # Mailerã¯ã©ã¹ # ã«ã¹ã¿ã Mailerãå©ç¨ããå ´åã¯ãããå¤æ´ããã # 詳細ã¯ã035 ã¡ã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºããããåç §ã # config.mailer = 'Devise::Mailer' # Devise::Mailerã®è¦ªã¯ã©ã¹ã # config.parent_mailer = 'ActionMailer::Base' # ==> ORMã®è¨å® # ORMããã¼ãããã # ActiveRcordã¨Mongoidããµãã¼ããã¦ããã require 'devise/orm/active_record' # ==> èªè¨¼å ¨è¬ã®è¨å® # èªè¨¼ãã¼ï¼ã¦ã¼ã¶ã¼ãèªè¨¼ããéã«å©ç¨ãããã¼ï¼ã # email以å¤ã®ãã¼ãå©ç¨ãããå ´åã«å¤æ´ããã # 詳細ã¯ã024 emailã®ä»£ããã«usernameã§ãã°ã¤ã³ãããããåç §ã # config.authentication_keys = [:email] # èªè¨¼ã«ä½¿ç¨ãããªã¯ã¨ã¹ããªãã¸ã§ã¯ãã®ãã©ã¡ã¼ã¿ã # config.request_keys = [] # 大æåå°æåãåºå¥ããªãèªè¨¼ãã¼ã # Userã®ä½æ/ä¿®æ£/èªè¨¼/æ¤ç´¢æã«å¤§æåå°æåãåºå¥ããªããã config.case_insensitive_keys = [:email] # 空ç½ãåé¤ããèªè¨¼ãã¼ã # Userã®ä½æ/ä¿®æ£/èªè¨¼/æ¤ç´¢æã«ç©ºç½ãåé¤ããã config.strip_whitespace_keys = [:email] # request.paramsã«ããèªè¨¼ãæå¹ã«ããã # `config.params_authenticatable = [:database]`ã¨ããã°DBèªè¨¼ï¼ã¡ã¼ã« + ãã¹ã¯ã¼ãï¼èªè¨¼ã®ã¿ãæå¹ã«ããã # config.params_authenticatable = true # HTTP Authã«ããèªè¨¼ãæå¹ã«ããã # `config.http_authenticatable = [:database]` ã¨ããã°DBèªè¨¼ã®ã¿ãæå¹ã«ããã # config.http_authenticatable = false # Ajaxãªã¯ã¨ã¹ãã«å¯¾ãã¦401ãè¿ãã # config.http_authenticatable_on_xhr = true # Basicèªè¨¼ã§å©ç¨ãããrealmã # config.http_authentication_realm = 'Application' # paranoidã¢ã¼ãã # ã¡ã¼ã«ã¢ãã¬ã¹ãç»é²ããã¦ãããã©ããã確èªããã®ãé²ãã # 詳細㯠https://github.com/heartcombo/devise/wiki/How-To:-Using-paranoid-mode,-avoid-user-enumeration-on-registerable # config.paranoid = true # userãsessionã«ä¿åããå¦çãã¹ãããããç®æã config.skip_session_storage = [:http_auth] # ã»ãã¥ãªãã£ã¼ã®ããèªè¨¼æã«CSRFãã¼ã¯ã³ãsessionããåé¤ããã # trueã ã¨ãµã¤ã³ã¤ã³ããµã¤ã³ã¢ããã§Ajaxã使ç¨ããå ´åããµã¼ãã¼ããæ°ããCSRFãã¼ã¯ã³ãåå¾ããå¿ è¦ãããã # config.clean_up_csrf_token_on_authentication = true # eager loadæã«ã«ã¼ãã£ã³ã°ããªãã¼ãããã # before_eager_loadããã¯ãå©ç¨ã # falseã«ããã¨ã¢ããªèµ·åãé«éã«ãªãããDeviseã®ãããã³ã°ããã¼ãããå¿ è¦ãããå ´åã¯æ£å¸¸ã«èµ·åã§ããªãã # config.reload_routes = true # ==> Database Authenticatableã¢ã¸ã¥ã¼ã«ã®è¨å® # ããã·ã¥åã®ã¬ãã«ã # ããã·ã¥åã«ã¯çµæ§æéããããã # bcryptï¼ããã©ã«ãã®ã¢ã«ã´ãªãºã ï¼ã®å ´åãã¬ãã«ã«å¿ãã¦ææ°é¢æ°çã«é ããªããä¾ãã°ã¬ãã«20ã§ã¯60ç§ç¨åº¦ãããã # ãã¹ãã®æã¯ã¬ãã«1ã«ãã¦é度ãä¸ããã # æ¬çªã§ã¯ã¬ãã«10以ä¸ã¯å©ç¨ãã¹ãã§ãªãã config.stretches = Rails.env.test? ? 1 : 12 # ããã·ã¥åããéã®pepperã # pepperã¯saltã¿ãããªãã¤ã # 詳細㯠https://stackoverflow.com/questions/6831796/whats-the-most-secure-possible-devise-configuration # config.pepper = '9a11b4eaf0250fec05630de0b518c3f63086fa403a8309d74408b3223d57a2312cef3ef746152f43c508da74b11cf21f982d9573ef552a186e36d83818129029' # emailå¤æ´æã«emailå¤æ´å®äºã¡ã¼ã«ãéä¿¡ããã # config.send_email_changed_notification = false # passwordå¤æ´æã«passwordå¤æ´å®äºã¡ã¼ã«ãéä¿¡ããã # config.send_password_change_notification = false # ==> Confirmableã¢ã¸ã¥ã¼ã«ã®è¨å® # confirmãªãã§ãã°ã¤ã³ã§ããæéã # ãããè¨å®ããã¨ä¸å®æéã¯confirmåã§ããã°ã¤ã³ã§ããããã«ãªãã # nilã«è¨å®ããã¨ç¡æéã«ãã°ã¤ã³ã§ããããã«ãªãã # ããã©ã«ã㯠0.daysãï¼confirmãªãã«ã¯ãã°ã¤ã³ã§ããªããï¼ # config.allow_unconfirmed_access_for = 2.days # confirmation_tokenã®æå¹æéã # ã¦ã¼ã¶ã¼ã¯ãã®æéå ã«confirmæ示ã¡ã¼ã«ã®ãªã³ã¯ãã¯ãªãã¯ããªãã¨ãããªãã # ããã©ã«ã㯠nilãï¼å¶éãªããï¼ # config.confirm_within = 3.days # ãµã¤ã³ã¢ããæã ãã§ãªããemailå¤æ´æã«ãConfirmã¡ã¼ã«ãéä¿¡ããã # unconfirmed_emailã«ã©ã ãå¿ è¦ã config.reconfirmable = true # confirmã®ãã¼ã # config.confirmation_keys = [:email] # ==> Rememberableã¢ã¸ã¥ã¼ã«ã®è¨å® # Sessionãåããã¾ã§ã®æéã # ããã©ã«ãã¯2.weeksã # config.remember_for = 2.weeks # ãã°ã¢ã¦ãæã«remember_tokenãæéåãã«ããã config.expire_all_remember_me_on_sign_out = true # cookieå©ç¨æã«æéã伸ã°ãã # config.extend_remember_period = false # cookieã«ã»ãããããªãã·ã§ã³ã # config.rememberable_options = {} # ==> Validatableã¢ã¸ã¥ã¼ã«ã®è¨å® # passwordã®é·ãã # Rangeã§æå®ããã®å ´åã¯6æåãã128æåã config.password_length = 6..128 # emailããªãã¼ã·ã§ã³ã§å©ç¨ããæ£è¦è¡¨ç¾ config.email_regexp = /\A[^@\s]+@[^@\s]+\z/ # ==> Timeoutableã¢ã¸ã¥ã¼ã«ã®è¨å® # ã¿ã¤ã ã¢ã¦ãæé # config.timeout_in = 30.minutes # ==> lockableã¢ã¸ã¥ã¼ã«ã®è¨å® # ããã¯æ¹æ³ # - failed_attempts: æå®åæ°ééããããã㯠# - none: èªåããã¯ã¯ãªãã§ããµã¼ã管çè ãæåã§ãã㯠# config.lock_strategy = :failed_attempts # ã¢ã³ããã¯ã®ãã¼ # config.unlock_keys = [:email] # ã¢ã³ããã¯æ¹æ³ # - email: ã¡ã¼ã«ã§ã¢ã³ããã¯ã®ãªã³ã¯ãéä¿¡ # - time: æ°æéå¾ã«ã¢ã³ããã¯ï¼config.unlock_inã¨ä¸ç·ã«ä½¿ãï¼ # - both: emailã¨timeã®ä¸¡æ¹ # - none: èªåã¢ã³ããã¯ã¯ãªãã§ããµã¼ã管çè ãæåã§ã¢ã³ãã㯠# config.unlock_strategy = :both # ããã¯ã¾ã§ã®åæ° # config.maximum_attempts = 20 # ã¢ã³ããã¯ã¾ã§ã®æéï¼`config.unlock_strategy = :time`ã®å ´åï¼ # config.unlock_in = 1.hour # ããã¯åã«è¦åãã # config.last_attempt_warning = true # ==> Recoverableã¢ã¸ã¥ã¼ã«ã®è¨å® # # ãã¹ã¯ã¼ããªã»ããæã«ãã¼ã«ãªãã«ã©ã ã # config.reset_password_keys = [:email] # ãã¹ã¯ã¼ããªã»ããã®æå¹æéã config.reset_password_within = 6.hours # ãã¹ã¯ã¼ããªã»ããå¾ã«èªåãã°ã¤ã³ã # config.sign_in_after_reset_password = true # ==> devise-encryptable gemã®è¨å® # bcrypt以å¤ã®ããã·ã¥åã¢ã«ã´ãªãºã ã # devise-encryptable gemã®ã¤ã³ã¹ãã¼ã«ãå¿ è¦ã # bcrypt以å¤ã®ã¢ã«ã´ãªãºã ã¯:sha1ã:sha512ã:clearance_sha1ã:authlogic_sha512ã:sha1ãªã©ã # config.encryptor = :sha512 # ==> Scopeã®è¨å® # Scopeç¨ã®ãã¥ã¼ãåªå çã«ä½¿ãããã«ãªãã # trueã«ããã¨`devise`åå空éã®ãã¥ã¼ã§ã¯ãªãã`users`ãªã©ã®Scope対å¿ã®ãã¥ã¼ãå©ç¨ããã # ããã©ã«ãã¯é«éåã®ãã`false`ã«è¨å®ããã¦ããã # 詳細ã¯ã023 è¤æ°ã¢ãã«ãå©ç¨ããããåç §ã # config.scoped_views = false # ããã©ã«ãã®Scopeã # é常ã§ããã°userã«ãªãã # config.default_scope = :user # ãã°ã¢ã¦ãæã«å ¨ã¦ã®Scopeã§ã®ãã°ã¢ã¦ãã¨ããã # falseã®å ´åã¯/users/sign_outã§ãã°ã¢ã¦ãããå ´åãuser Scopeã ããã°ã¢ã¦ãã«ãªãã # config.sign_out_all_scopes = true # ==> Navigationã®è¨å® # ããã²ã¼ã·ã§ã³ã¨ãã¦æ±ããããã©ã¼ãããã®ãªã¹ãã # config.navigational_formats = ['*/*', :html] # ãã°ã¢ã¦ãæã®HTTPã¡ã½ãã config.sign_out_via = :delete # ==> OmniAuthã®è¨å® # OmniAuthã®è¨å®ã # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' # ==> Wardenã®è¨å® # Wardenã®è¨å®ã # strategy追å ãããfailure_appå¤æ´ãããã # # config.warden do |manager| # manager.intercept_401 = false # manager.default_strategies(scope: :user).unshift :some_external_strategy # end # ==> Mountable Engineã®è¨å® # Mountable Engineã§ä½¿ãéã®routeråã # config.router_name = :my_engine # # OmniAuthã®pathã # OmniAuthãå©ç¨ããå ´åã«è¨å®ããã # config.omniauth_path_prefix = '/my_engine/users/auth' # ==> Turbolinksã®è¨å® # Turbolinksãå©ç¨ãã¦ããå ´åããªãã¤ã¬ã¯ããæ£ããåä½ãããããã«Turbolinks::Controllerãincludeããã # # ActiveSupport.on_load(:devise_failure_app) do # include Turbolinks::Controller # end # ==> Registerableã¢ã¸ã¥ã¼ã«ã®è¨å® # ãã¹ã¯ã¼ãå¤æ´å¾ã«èªåçã«ãµã¤ã³ã¤ã³ãããã # config.sign_in_after_change_password = true end
åè
第10ç« ãã®ä»ã®ã«ã¹ã¿ãã¤ãºï¼Wikiã¾ã¨ãï¼
ð± Deviseã®Wikiï¼ https://github.com/heartcombo/devise/wiki ï¼ã«ã¯ããããªã«ã¹ã¿ãã¤ãºã®ããæ¹ãæ¸ããã¦ããããWikiã®ä¸ãããç¥ã£ã¦ããã¨å½¹ç«ã¡ãããªã«ã¹ã¿ãã¤ãºãã¾ã¨ãã¦ãããã
041 ãã¹ã¯ã¼ãå¤æ´æã«ãã°ã¢ã¦ããããªã
ð± Deviseã®ä»æ§ã§ããã°ã¤ã³ä¸ã«ã¦ã¼ã¶ã¼ããã¹ã¯ã¼ããå¤æ´ããã¨èªåçã«ãã°ã¢ã¦ãç¶æ
ã«ãªã£ã¦ãã¾ããããã°ã¤ã³ç¶æ
ãç¶æããããã«ã¯bypass_sign_in(user)
ãå©ç¨ããã°OKã ããsign_in(user, :bypass => true)
ã使ãæ¹æ³ã¯deprecatedãªã®ã§æ³¨æãã¦ãã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
- How To: Allow users to edit their password · heartcombo/devise Wiki · GitHub
- ruby on rails - Devise logging out automatically after password change - Stack Overflow
- Deviseã§ãã¹ã¯ã¼ãå¤æ´æã«ãã°ã¢ã¦ãããªãæ¹æ³ - ã¯ã·ã¯ã¯ã·ãè²ã¦ã
- Deviseã§ãã¹ã¯ã¼ãå¤æ´ããå ´åã®ãã°ã¢ã¦ããé²ã | èªè»¢è»ã§éå¤ãã¾ããâªããã°
042 Deviseã«ç¬èªã®èªè¨¼æ¹æ³ï¼Strategyï¼ã追å ãã
ð± Deviseã¯Wardenãå©ç¨ãã¦ãããããç¬èªã®Strategyã¯ã©ã¹ãå®ç¾©ãããã¨ã§ãç¬èªã®èªè¨¼æ¹æ³ã追å ã§ãããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãããã¨057 Wardenãåèã«ãªããã
- How To: Authenticate via LDAP · heartcombo/devise Wiki · GitHub
- Rails/Deviseãå©ç¨ããèªè¨¼ã Amazon Cognito èªè¨¼ã«å§è²ãã - stmn tech blog
- deviseã®ç¬èªã¹ãã©ãã¸ã¼ã®ä½ãæ¹ - Adwaysã¨ã³ã¸ãã¢ããã°
- Deviseã«ç¬èªã®strategyãå ¥ãã - ãããã´ã®ããã°
043 ã²ã¹ãã¦ã¼ã¶ã¼æ©è½ãå®è£ ãã
ð± ã²ã¹ãã¦ã¼ã¶ã¼æ©è½ã¯ãµã¤ã³ã¢ããç¡ãã§ã¢ããªã±ã¼ã·ã§ã³ãå©ç¨ã§ããããã«ãªãæ©è½ã ããã¦ã¼ã¶ã¼ã¯å人æ å ±ãæä¾ããã«ã¢ããªã±ã¼ã·ã§ã³ã試ããããã«ãªããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
- How To: Create a guest user · heartcombo/devise Wiki · GitHub
- #393 Guest User Record - RailsCasts
- ç°¡åãã°ã¤ã³ã»ã²ã¹ããã°ã¤ã³æ©è½ã®å®è£ æ¹æ³ï¼ãã¼ããã©ãªãªç¨ï¼ - Qiita
- [Rails] devise ãå©ç¨ãã²ã¹ãã¦ã¼ã¶ã¼æ©è½( ãã¼ããã©ãªãª ç¨) - Qiita
044 ã¢ã«ã¦ã³ãåé¤ãè«çåé¤ã«ãã
ð± ã¢ã«ã¦ã³ãåé¤ãããã¨ãããã©ã«ãã§ã¯usersã¬ã³ã¼ããç©çåé¤ãããããããè«çåé¤ã«å¤æ´ãã¦ãusersã¬ã³ã¼ãã¯æ®ããã¾ã¾ãã°ã¤ã³ã§ããªãããã«ãããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
- How to: Soft delete a user when user deletes account · heartcombo/devise Wiki · GitHub
- ã翻訳ãdeviseã§è«çåé¤ãå®è£ ããæ¹æ³ - Qiita
- [Rails]paranoiaã使ããã«éä¼æ©è½ãå®è£ ãã(ã¦ã¼ã¶ã¼ãè«çåé¤ãã) - Qiita
045 管çè 権éãç¨æãã
ð± Deviseã§ç®¡çè
ãç¨æããã«ã¯ãUserã¢ãã«ä»¥å¤ã«Adminã¢ãã«ãç¨æããæ¹æ³ãããããï¼023 è¤æ°ã¢ãã«ãå©ç¨ããï¼ãå¥ã®ããæ¹ã¨ãã¦ãã¢ãã«ã¯User1ã¤ã ãã«ãã¦ãroleã®ãããªã«ã©ã ã§ç®¡çè
権éãå©ç¨ããæ¹æ³ãããããDeviseãèªè¨¼ã®gemã§ããã®ã«å¯¾ãã¦ããã®æ¨©éã®ç®¡çã«ã¯èªå¯ã®gemãå©ç¨ãããã ãèªå¯ã®gemã¨ãã¦ã¯CanCanCan
ã¨Pundit
ã®2ã¤ãæåã ãããã®2ã¤ã¯ã§ãããã¨ã¯ã»ã¨ãã©åããªã®ã§ãã©ã¡ãã好ããªæ¹ãå©ç¨ããã°OKã ããCanCanCanããã¼ã«èµ·ç¹ã§æ¨©éãå®ç¾©ããã®ã«å¯¾ãã¦ãPunditã¯ãªã½ã¼ã¹èµ·ç¹ã§æ¨©éãå®ç¾©ãããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
CanCanCan
- GitHub - CanCanCommunity/cancancan: The authorization Gem for Ruby on Rails.
- How to use CanCan / CanCanCan - Qiita
Pundit
- GitHub - varvet/pundit: Minimal authorization through OO design and pure Ruby classes
- Pundit + Railsã§èªå¯ã®ä»çµã¿ãã·ã³ãã«ã«ä½ã - Qiita
046 emailã¨usernameã©ã¡ãã§ããã°ã¤ã³ã§ããããã«ãã
ð± é常ã ã¨emailã§ãã°ã¤ã³ãããã©ããããemailã¨usernameã©ã¡ãã§ããã°ã¤ã³ã§ããããã«ãªã£ããå¬ãããããUserã¢ãã«ã«emailå±æ§ã¨usernameå±æ§ã®2å½¹ãããªãlogin
ã¨ããä»®æ³å±æ§ãç¨æããã°å®ç¾ã§ãããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
- How To: Allow users to sign in using their username or email address · heartcombo/devise Wiki · GitHub
- Rails deviseã«ããã¦ã¼ã¶ã¼èªè¨¼ ã¡ã¼ã«ã«ããèªè¨¼ãemailã¨usernameã®ã©ã¡ãã§ããã°ã¤ã³å¯è½ã«ããã¾ã§ - Qiita
- Rails4.1ã§deviseã®ãã°ã¤ã³IDãemailã¨usernameã®ã©ã¡ãã§ãå¯è½ã«ãã - Qiita
047 ãã¹ã¯ã¼ãå ¥åãªãã§ã¢ã«ã¦ã³ãæ å ±ãå¤æ´ãã
ð± ã¢ã«ã¦ã³ãç·¨éç»é¢ï¼/users/edit
ï¼ã§èªåã®ã¢ã«ã¦ã³ãæ
å ±ãå¤æ´ããããã«ã¯ãç¾å¨ã®ãã¹ã¯ã¼ãã®å
¥åãå¿
é ã ããããããã¹ã¯ã¼ããªãã§å¤æ´ã§ããããã«ãããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
- How To: Allow users to edit their account without providing a password · heartcombo/devise Wiki · GitHub
- Devise ã§ã¦ã¼ã¶ã¼ããã¹ã¯ã¼ããªãã§ã¢ã«ã¦ã³ãæ å ±ãå¤æ´ããã®ãè¨±å¯ | EasyRamble
048 ãã¹ã¯ã¼ããbcrypt以å¤ã®æ¹æ³ã§ããã·ã¥åãã
ð± Deviseã§ã¯ããã©ã«ãã§bcryptã使ããã¹ã¯ã¼ããããã·ã¥åããããdevise-encryptable
gemã使ããã¨ã§å¥ã®æ¹æ³ã§ããã·ã¥åã§ããããã«ãªããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
- How To: Create a custom encryptor · heartcombo/devise Wiki · GitHub
- GitHub - heartcombo/devise-encryptable: Devise encryptable behavior since v2.1
- deviseã®æå·åã¢ã«ã´ãªãºã ã®å¤æ´æ¹æ³ - aik's blog
049 ã¡ã¼ã«ã¢ãã¬ã¹å¤æ´æã«ãConfirmæ示ã¡ã¼ã«ãéä¿¡ãã
ð± Confirmableã¢ã¸ã¥ã¼ã«ã¯ããã©ã«ãã§ã¯ã¡ã¼ã«ã¢ãã¬ã¹å¤æ´æã«ã¯Confirmæ示ã¡ã¼ã«ãéä¿¡ããªããããããä¿®æ£ããã«ã¯config.reconfirmable = true
ã¨ããè¨å®ãããå¿
è¦ããããã詳ããã¯ä»¥ä¸ã®è¨äºãåèã«ãã¦ãã
- Devise ã§ã¡ã¼ã«ã¢ãã¬ã¹å¤æ´æã«ã確èªã¡ã¼ã«ãåºã - ããããwebãµã¼ãã¹éçºæ¥è¨
- Devise - emailæ´æ°æã«ç¢ºèªã¡ã¼ã«ãéã(reconfirmable) - Qiita
第11ç« Tips
050 userãserializeãã
ð¦ð» Railsã³ã³ã½ã¼ã«ã§Userã¤ã³ã¹ã¿ã³ã¹ãè¦ãã¨encrypted_password
ãªã©ã®å±æ§ã表示ãããªããï¼ãªãã§ï¼
irb(main):009:0> User.first => #<User id: 2, email: "[email protected]", created_at: "2020-11-06 06:06:36", updated_at: "2020-11-06 06:06:36">
ð± Deviseã§ã¯ã»ãã¥ãªãã£ã¼ä¸ã®é½åã§ãå¿
è¦ãªã«ã©ã ã ããã·ãªã¢ã©ã¤ãºããããã«ãªã£ã¦ããã ãusersãã¼ãã«ã«encrypted_password
ï¼ããã·ã¥åããããã¹ã¯ã¼ãï¼ãcurrent_sign_in_ip
ï¼ãµã¤ã³ã¤ã³æã®IPã¢ãã¬ã¹ï¼ã«ã©ã ãªã©ã®ã»ã³ã·ãã£ããªæ
å ±ãæããããã¨ã«ãªãã§ããï¼Userã¤ã³ã¹ã¿ã³ã¹ã丸ãã¨ã·ãªã¢ã©ã¤ãºãã¦ãã¾ãã¨ãå ´åã«ãã£ã¦ã¯ãããã®æ
å ±ãæ¼ãã¦ãã¾ãå¯è½æ§ããããã ãã ããDeviseã§ã¯serializable_hash
ããªã¼ãã¼ã©ã¤ããã¦ã»ã³ã·ãã£ããªæ
å ±ã¯ã·ãªã¢ã©ã¤ãºãããªãããã«ãã¦ãããã ããRailsã³ã³ã½ã¼ã«ã§ã¯Userã¤ã³ã¹ã¿ã³ã¹ã®ç¶æ
ãinspect
ã使ã£ã¦è¡¨ç¤ºããããã©ãinspect
ãserializable_hash
ãå©ç¨ããããã«ãªã¼ãã¼ã©ã¤ãããã¦ãããããRailsã³ã³ã½ã¼ã«ã§ã¯encrypted_password
ãªã©ã®ã«ã©ã æ
å ±ã表示ãããªãããã«ãªã£ã¦ãããã
irb(main):016:0> User.first.serializable_hash => {"id"=>2, "email"=>"[email protected]", "created_at"=>Fri, 06 Nov 2020 06:06:36 UTC +00:00, "updated_at"=>Fri, 06 Nov 2020 06:06:36 UTC +00:00}
ð± å ·ä½çã«ã¯ä»¥ä¸ã®å±æ§ã¯ã·ãªã¢ã©ã¤ãºãããªããã
encrypted_password reset_password_token reset_password_sent_at remember_created_at sign_in_count current_sign_in_at last_sign_in_at current_sign_in_ip last_sign_in_ip password_salt confirmation_token confirmed_at confirmation_sent_at remember_token unconfirmed_email failed_attempts unlock_token locked_at
ð± serializable_hash(force_except: true)
ã使ã£ããattributes
ã使ãã°encrypted_password
fãªã©ã®æ
å ±ã«ãã¢ã¯ã»ã¹ã§ãããã
irb(main):017:0> User.first.serializable_hash(force_except: true) => {"id"=>2, "email"=>"[email protected]", "encrypted_password"=>"$2a$12$9Fiz99wL33TIw8JeDP2Vb..y99m5i0JrMY8pjeekmumXNOwM1ncbS", "reset_password_token"=>nil, "reset_password_sent_at"=>nil, "remember_created_at"=>nil, "created_at"=>Fri, 06 Nov 2020 06:06:36 UTC +00:00, "updated_at"=>Fri, 06 Nov 2020 06:06:36 UTC +00:00}
irb(main):018:0> User.first.attributes => {"id"=>2, "email"=>"[email protected]", "encrypted_password"=>"$2a$12$9Fiz99wL33TIw8JeDP2Vb..y99m5i0JrMY8pjeekmumXNOwM1ncbS", "reset_password_token"=>nil, "reset_password_sent_at"=>nil, "remember_created_at"=>nil, "created_at"=>Fri, 06 Nov 2020 06:06:36 UTC +00:00, "updated_at"=>Fri, 06 Nov 2020 06:06:36 UTC +00:00}
åè
- devise/authenticatable.rb at master · heartcombo/devise · GitHub
- ãã¼ãã§ã¯ãRailsèè ã解説ããdeviseã®ç¾ä»£çãªã¦ã¼ã¶ã¼èªè¨¼ã®ã¢ãã«æ§æã«ã¤ã㦠- joker1007âs diary
051 ã¢ãã«ããcurrent_userã«ã¢ã¯ã»ã¹ãã
ð¦ð» ã¢ãã«ããcurrent_userã«ã¢ã¯ã»ã¹ãããã®ã ãã©ãã©ãããã°ããï¼
ð± ActiveSupport::CurrentAttributes
ãå©ç¨ããã°å¯è½ã ããActiveSupport::CurrentAttributes
ãç¶æ¿ããã¯ã©ã¹ã¯ãªã¯ã¨ã¹ãæ¯ã«å±æ§ããªã»ãããããããããªã¯ã¨ã¹ãæ¯ã«ç¬ç«ããç¶æ
ãæã¦ãããã«ãªããã ã
ð± ã¾ãActiveSupport::CurrentAttributes
ãç¶æ¿ããCurrent
ã¯ã©ã¹ãå®ç¾©ãããã
class Current < ActiveSupport::CurrentAttributes # ãã®å±æ§ãcurrent_userã«ãªã # ãã®å±æ§ã¯ãªã¯ã¨ã¹ãæ¯ã«ãªã»ããããã attribute :user end
ð± application_controller.rbã®before_action
ã§Current.user
ã«current_user
ãã»ãããããã
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base before_action :set_current_user def set_current_user Current.user = current_user end end
ð± ããã§ã¢ãã«ããcurrent_uesr
ã«ã¢ã¯ã»ã¹ã§ããããã«ãªããã
# ã¢ãã« class Article < ApplicationRecord scope :current, -> { where(user: Current.user) } end
Article.current #=> current_userã®articles
ð± ãã ãActiveSupport::CurrentAttributes
ã®å©ç¨ã¯åºæ¬çã«ã¯ã¢ã³ããã¿ã¼ã³ã ã¨æãã®ã§ãã§ããã°é¿ããã¹ãããªãã¨æãããActiveSupport::CurrentAttributes
ã¯ã°ãã¼ãã«å¤æ°ã®ãããªãã®ã§ã©ãããã§ãã¢ã¯ã»ã¹ã§ãã¦ãã¾ããããMVCãå£ãã¦ã³ã¼ããã«ãªã¹ã«ãªã£ã¡ãããã ããã¨Railsã³ã³ã½ã¼ã«ã§ã®å©ç¨ã¨ãããªã¯ã¨ã¹ãããªãç¶æ
ã ã¨ã¨ã©ã¼ã«ãªã£ã¡ãããããã¢ãã«ã§current_user
ãå¿
è¦ã«ãªãå ´åã¯ãcurrent_userãå¼æ°ã¨ãã¦æ¸¡ãããcurrent_user.articles
ã®ããã«é¢é£ã使ããããã»ãããããã
åè
052 ãã¹ã
ð± Deviseã®æ©è½ããã¹ãã§ä½¿ãã«ã¯ãã«ãã¼ã¢ã¸ã¥ã¼ã«ãincludeããã°OKã ãã
# ã³ã³ããã¼ã©ã¼ãã¹ãã®å ´å class PostsControllerTest < ActionController::TestCase include Devise::Test::ControllerHelpers end # Integrationãã¹ãã®å ´å class PostsTests < ActionDispatch::IntegrationTest include Devise::Test::IntegrationHelpers end
ð± RSpecã®å ´åã¯è¨å®ãã¡ã¤ã«ã§includeãã¦ãã
RSpec.configure do |config| # ã³ã³ããã¼ã©ã¼ãã¹ãã®å ´å config.include Devise::Test::ControllerHelpers, type: :controller # Integrationãã¹ãã®å ´å config.include Devise::Test::IntegrationHelpers, type: :request end
ð± ããã§ãã¹ãã§ãã«ãã¼ã¡ã½ããã¨ãã¦sign_in
ã¨sign_out
ã使ããããã«ãªããã
# ãã¹ã # ãã°ã¤ã³ sign_in user # ãã°ã¤ã³(ã¹ã³ã¼ãæå®) sign_in user, scope: :admin # ãã°ã¢ã¦ã sign_out user # ãã°ã¢ã¦ã(Scopeæå®) sign_out :admin
第12ç« Deviseã®ã¨ã³ã·ã¹ãã
ð± Deviseã¯Railsã®èªè¨¼gemã®ä¸ã§ã¯ä¸çªäººæ°ãããã®ã§ãDeviseé¢ä¿ã®ä¾¿å©ãªgemãããããåå¨ããããããã§ã¯ãããªgemã®ä¸ã§ãã¨ããã便å©ãªgemãç´¹ä»ãã¦ãããã
053 AnyLogin - ãã°ã¤ã³ã¦ã¼ã¶ã¼ãåãæ¿ãã
ð± éçºç°å¢ã§ãã°ã¤ã³ã¦ã¼ã¶ã¼ãåãæ¿ããã®ã£ã¦é¢åã ããï¼ãã¡ãã¡ãã°ã¤ã³ãç´ããªãããããªãã£ãããã¦ã¼ã¶ã¼ã®ãã¹ã¯ã¼ããè¦ãã¦ãããªãããããªãã£ãããAnyLoginã使ãã¨ãã°ã¤ã³ã¦ã¼ã¶ã¼ããããããã¦ã³ããé¸æã§ããããã«ãªããã
AnyLoginã使ã£ã¦ã¿ãã
ð± ã¾ãã¯AnyLoginãã¤ã³ã¹ãã¼ã«ãã¦ãã
# Gemfile gem 'any_login'
$ bundle install
ð± application.html.erb
ã«ä»¥ä¸ã®ã³ã¼ãã追å ãã¦ãã
# app/views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title>DemoApp</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <%= yield %> <!-- ãã®è¡ã追å --> <%= any_login_here if defined?(AnyLogin) %> </body> </html>
ð± ããã§ç»é¢ã®å·¦ä¸ãããã°ã¤ã³ã¦ã¼ã¶ã¼ãé¸æã§ããããã«ãªããã
è¨å®ãå¤æ´ãã
ð± ã¸ã§ãã¬ã¼ã¿ã使ã£ã¦è¨å®ãã¡ã¤ã«ãä½æãã¦ãã
$ rails g any_login initializer create config/initializers/any_login.rb
ð± è¨å®ãã¡ã¤ã«ã®è¨å®é ç®ã¯ãããªæãã ãã
AnyLogin.setup do |config| # provider (:devise, :authlogic, sorcery, clearance)ãæå®ãããGemfileããèªåçã«å¤å®ãããã®ã§nilã®ã¾ã¾ã§OKã ãã config.provider = nil # æå¹ã«ãããã©ãããåºæ¬çã«ã¯'development'ã ãæå¹ã«ããã°OKã ãã config.enabled = Rails.env.to_s == 'development' # èªè¨¼å¯¾è±¡ã®ã¢ãã«ã¯ã©ã¹åãããã¦ãã¯Userã§OK config.klass_name = 'User' # Userã®ã³ã¬ã¯ã·ã§ã³ãè¿ãã¡ã½ãããæå®ãããã©ã¯User.all config.collection_method = :all # ã»ã¬ã¯ãããã¯ã¹ã®ãã©ã¼ããã config.name_method = proc { |e| [e.email, e.id] } # ãã°ã¤ã³ã¦ã¼ã¶ã¼é¸æå¾ã®ãªãã¤ã¬ã¯ãå config.redirect_path_after_login = :root_path # ãã°ã¤ã³çºç«ã¤ãã³ã(change, click, both) config.login_on = :both # 表示ä½ç½®(top_left, top_right, bottom_left, bottom_right) config.position = :bottom_left # ãã°ã¤ã³ãã¿ã³ã®ã©ãã« config.login_button_label = 'Login' # ã»ã¬ã¯ãããã¯ã¹ã®ããã³ãã config.select_prompt = "Select #{AnyLogin.klass_name}" # ããã©ã«ãã§ãã°ã¤ã³ã¦ã¼ã¶ã¼é¸æformãå±éãã config.auto_show = false # limit(æ°å¤ or :none) config.limit = 10 # ãã¼ã·ãã¯èªè¨¼ON config.http_basic_authentication_enabled = false # ãã¼ã·ãã¯èªè¨¼(ã¦ã¼ã¶ã¼å) config.http_basic_authentication_user_name = 'any_login' # ãã¼ã·ãã¯èªè¨¼(ãã¹ã¯ã¼ã) config.http_basic_authentication_password = 'password' # controllerã使ã£ã表示ON/OFFæ¡ä»¶ config.verify_access_proc = proc { |controller| true } end
åè
054 devise-i18n - ãã¥ã¼ãæ¥æ¬èªåãã
ð± devise-i18nã¨ããgemã使ãã¨ãã¥ã¼ãæ¥æ¬èªåã§ãããã詳ããã¯039 ãã¥ã¼ãæ¥æ¬èªåãããåç §ãã¦ãã
055 DeviseInvitable - æå¾ æ©è½ã追å ãã
DeviseInvitableã使ã£ã¦ã¿ãã
ð± DeviseInvitableã¯æå¾ æ©è½ãDeviseã«è¿½å ããgemã ããInvitableã¢ã¸ã¥ã¼ã«ãå©ç¨ãããã¨ã§ãæå®ãããã¡ã¼ã«ã¢ãã¬ã¹ã«æå¾ ç¶ãéä¿¡ã§ããããã«ãªããã
ð± ã¾ãã¯DeviseInvitableãã¤ã³ã¹ãã¼ã«ãããã
# Gemfile gem 'devise_invitable'
$ bundle install
ð± ã¸ã§ãã¬ã¼ã¿ã¼ãå®è¡ãã¦ãå¿ è¦ãªãã¡ã¤ã«ãä½æãã¦ãã
$ rails g devise_invitable:install insert config/initializers/devise.rb create config/locales/devise_invitable.en.yml
ð± config/initializers/devise.rb
ã«DeviseInvitableç¨ã®è¨å®ã追å ããããã
# config/initializers/devise.rb # 追å é¨åã®ã¿ # ==> Configuration for :invitable # The period the generated invitation token is valid. # After this period, the invited resource won't be able to accept the invitation. # When invite_for is 0 (the default), the invitation won't expire. # config.invite_for = 2.weeks # Number of invitations users can send. # - If invitation_limit is nil, there is no limit for invitations, users can # send unlimited invitations, invitation_limit column is not used. # - If invitation_limit is 0, users can't send invitations by default. # - If invitation_limit n > 0, users can send n invitations. # You can change invitation_limit column for some users so they can send more # or less invitations, even with global invitation_limit = 0 # Default: nil # config.invitation_limit = 5 # The key to be used to check existing users when sending an invitation # and the regexp used to test it when validate_on_invite is not set. # config.invite_key = { email: /\A[^@]+@[^@]+\z/ } # config.invite_key = { email: /\A[^@]+@[^@]+\z/, username: nil } # Ensure that invited record is valid. # The invitation won't be sent if this check fails. # Default: false # config.validate_on_invite = true # Resend invitation if user with invited status is invited again # Default: true # config.resend_invitation = false # The class name of the inviting model. If this is nil, # the #invited_by association is declared to be polymorphic. # Default: nil # config.invited_by_class_name = 'User' # The foreign key to the inviting model (if invited_by_class_name is set) # Default: :invited_by_id # config.invited_by_foreign_key = :invited_by_id # The column name used for counter_cache column. If this is nil, # the #invited_by association is declared without counter_cache. # Default: nil # config.invited_by_counter_cache = :invitations_count # Auto-login after the user accepts the invite. If this is false, # the user will need to manually log in after accepting the invite. # Default: true # config.allow_insecure_sign_in_after_accept = false
ð± devise_invitable.en.yml
ã¨ããDeviseInvitableç¨ã®ãã±ã¼ã«ãã¡ã¤ã«ãä½æããããã
en: devise: failure: invited: "You have a pending invitation, accept it to finish creating your account." invitations: send_instructions: "An invitation email has been sent to %{email}." invitation_token_invalid: "The invitation token provided is not valid!" updated: "Your password was set successfully. You are now signed in." updated_not_active: "Your password was set successfully." no_invitations_remaining: "No invitations remaining" invitation_removed: "Your invitation was removed." new: header: "Send invitation" submit_button: "Send an invitation" edit: header: "Set your password" submit_button: "Set my password" mailer: invitation_instructions: subject: "Invitation instructions" hello: "Hello %{email}" someone_invited_you: "Someone has invited you to %{url}, you can accept it through the link below." accept: "Accept invitation" accept_until: "This invitation will be due in %{due_date}." ignore: "If you don't want to accept the invitation, please ignore this email. Your account won't be created until you access the link above and set your password." time: formats: devise: mailer: invitation_instructions: accept_until_format: "%B %d, %Y %I:%M %p"
ð± ã¸ã§ãã¬ã¼ã¿ã¼ã使ã£ã¦Invitableã¢ã¸ã¥ã¼ã«ã§å¿
è¦ã¨ãªãã³ã¼ãã追å ããããUserã¢ãã«ã«:invitable
ã追å ããã¦ãInvitableã¢ã¸ã¥ã¼ã«ç¨ã®ãã¤ã°ã¬ã¼ã·ã§ã³ãã¡ã¤ã«ãä½æããããã
$ rails g devise_invitable User insert app/models/user.rb invoke active_record create db/migrate/20201110133651_devise_invitable_add_to_users.rb
# app/models/user.rb class User < ApplicationRecord # invitableã¢ã¸ã¥ã¼ã«ã追å ããã¦ãã devise :invitable, :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable end
# db/migrate/20201110133651_devise_invitable_add_to_users.rb class DeviseInvitableAddToUsers < ActiveRecord::Migration[6.0] def up change_table :users do |t| t.string :invitation_token t.datetime :invitation_created_at t.datetime :invitation_sent_at t.datetime :invitation_accepted_at t.integer :invitation_limit t.references :invited_by, polymorphic: true t.integer :invitations_count, default: 0 t.index :invitations_count t.index :invitation_token, unique: true # for invitable t.index :invited_by_id end end def down change_table :users do |t| t.remove_references :invited_by, polymorphic: true t.remove :invitations_count, :invitation_limit, :invitation_sent_at, :invitation_accepted_at, :invitation_token, :invitation_created_at end end end
ð± ãã¤ã°ã¬ã¼ã·ã§ã³ãå®è¡ãã¦ãã
$ rails db:migrate
ð± ãã¥ã¼ã«æå¾
ã¡ã¼ã«éä¿¡ç»é¢ï¼/users/invitation/new
ï¼ã¸ã®ãªã³ã¯ãç½®ãã¦ãã
<%= link_to "æå¾ ã¡ã¼ã«éä¿¡ç»é¢", new_user_invitation_path %>
ð± ããã§æå¾ æ©è½ã使ããããã«ãªã£ããã
ð± 試ãã«ãªã³ã¯ãè¸ãã§ã¿ã¦ãããªã³ã¯ãè¸ãã¨æå¾
ã¡ã¼ã«éä¿¡ç»é¢ï¼/users/invitation/new
ï¼ã«é·ç§»ãããã
ð± ããã§ã¡ã¼ã«ã¢ãã¬ã¹ãå ¥åãã¦submitããã¨ãå ¥åãããã¡ã¼ã«ã¢ãã¬ã¹ã«æå¾ ã¡ã¼ã«ãéä¿¡ããããã
ð± ã¡ãªã¿ã«ãã®æç¹ã§æå¾ ãããã¦ã¼ã¶ã¼ã®usersã¬ã³ã¼ãã¯ä½æããã¦ããããã¾ã æ£å¼ãªã¦ã¼ã¶ã¼ç»é²ã¯ããã¦ããªãã®ã§ãã°ã¤ã³ã¯ã§ããªããã©ãã
ð± ã¡ã¼ã«ãåãåã£ã人ï¼æå¾
ããã人ï¼ã¯ã¡ã¼ã«å
ã®ãAccept invitationããªã³ã¯ãè¸ãã¨ãacceptç»é¢ï¼/users/invitation/accept
ï¼ã«é·ç§»ãããã
ð± ãã¹ã¯ã¼ããå ¥åãã¦submitããã¨ãæ£å¼ãªã¦ã¼ã¶ã¼ç»é²ã«ãªããã
Invitableã¢ã¸ã¥ã¼ã«ã®ã³ã³ããã¼ã©ã¼ã¨ã«ã¼ãã£ã³ã°
ð± Invitableã¢ã¸ã¥ã¼ã«ã§ã¯Devise::InvitationsController
ã¨ããã³ã³ããã¼ã©ã¼ãç¨æããããã
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/invitation/accept | devise/invitations#edit | acceptç»é¢ï¼ãã¹ã¯ã¼ãè¨å®ç»é¢ï¼ |
GET | /users/invitation/new | devise/invitations#new | æå¾ ã¡ã¼ã«éä¿¡ç»é¢ |
PATCH/PUT | /users/invitation | devise/invitations#update | accept |
POST | /users/invitation | devise/invitations#create | æå¾ ã¡ã¼ã«éä¿¡ |
GET | /users/invitation/remove | devise/invitations#destroy | æå¾ åãæ¶ã |
Invitableã¢ã¸ã¥ã¼ã«ã®ã¡ã½ãã
ð± Invitableã¢ã¸ã¥ã¼ã«ã使ãã¨ãããã¤ã便å©ãªã¡ã½ãããUserã«è¿½å ãããããæå¾ ç¶ã®éä¿¡ã¯é常ã§ããã°ç¨æãããã³ã³ããã¼ã©ã¼ããè¡ãã®ã§ããããã®ã¡ã½ãããç´æ¥ä½¿ããã¨ã¯å°ãªããã©ãæåã§æä½ãããå ´åã«ã¯ãããã®ã¡ã½ããã使ããã¨ã«ãªããã
# æå¾ ç¶ãéã # ã¦ã¼ã¶ã¼ãä½æããæå¾ ã¡ã¼ã«ãéä¿¡ãã # ãã®å ´åã¯[email protected]ã«ã¡ã¼ã«ãéä¿¡ãã User.invite!(email: '[email protected]', name: 'John Doe') # ã¦ã¼ã¶ã¼ãä½æããæå¾ ã¡ã¼ã«ã¯éä¿¡ããªãï¼ãããã¯ã§æå®ï¼ User.invite!(email: '[email protected]', name: 'John Doe') do |u| u.skip_invitation = true end # ã¦ã¼ã¶ã¼ãä½æããæå¾ ã¡ã¼ã«ã¯éä¿¡ããªãï¼ãªãã·ã§ã³ã§æå®ï¼ User.invite!(email: '[email protected]', name: 'John Doe', skip_invitation: true) # ã¦ã¼ã¶ã¼ä½æå¾ã«æå¾ ã¡ã¼ã«ãéä¿¡ãã # current_userã¯invited_by User.find(42).invite!(current_user) # invitation_tokenã§æ¤ç´¢ãã User.find_by_invitation_token(params[:invitation_token], true) # invitation_tokenã使ããæå¾ ãåãå ¥ãã User.accept_invitation!(invitation_token: params[:invitation_token], password: 'ad97nwj3o2', name: 'John Doe') # invitation_accepted_atãnilã®User User.invitation_not_accepted # invitation_accepted_atãnilã§ãªãUser User.invitation_accepted # æå¾ ã§ä½ãããã¦ã¼ã¶ã¼ User.created_by_invite
Invitableã¢ã¸ã¥ã¼ã«ã®è¨å®
ð± è¨å®ãå¤æ´ãããå ´åã¯è¨å®ãã¡ã¤ã«ã§å¤æ´ãã¦ãã
# config/initializers/devise.rb config.invite_for = 2.weeks
ð± ãããã¯Userã¢ãã«ã®ãªãã·ã§ã³ã¨ãã¦æå®ãããã¨ãã§ãããã
# app/models/user.rb devise :database_authenticatable, :confirmable, :invitable, invite_for: 2.weeks
ð± è¨å®é ç®ã¯ãããªæãã ãã
# config/initializers/devise.rb # invitation_tokenã®æå¹æé # æå¹æéãéããå ´åã¯æå¾ ãç¡å¹ã«ãªã # 0ã«è¨å®ããã¨æå¹æéãªãã«ãªã # ããã©ã«ã: 0 # config.invite_for = 2.weeks # ã¦ã¼ã¶ã¼ãéä¿¡ã§ããæå¾ ã¡ã¼ã«ã®ä¸éæ° # nilã®å ´åã¯ç¡å¶éã«ãªããinvitation_limitã¯å©ç¨ãããªã # 0ã®å ´åã¯éä¿¡ã§ããªããªãããæåã§ã«ã©ã ã®å¤ãå¤æ´ããã°éä¿¡å¯è½ # ããã©ã«ã: nil # config.invitation_limit = 5 # æå¾ ã¡ã¼ã«ãéä¿¡ããéã«æ¢åã¦ã¼ã¶ã¼ããã§ãã¯ããããã®ãã¼ # ããã©ã«ã: emailã«å¯¾ãã¦Devise.email_regexpã§ãã§ãã¯ãã # config.invite_key = { email: /\A[^@]+@[^@]+\z/ } # config.invite_key = { email: /\A[^@]+@[^@]+\z/, username: nil } # æå¾ ã¦ã¼ã¶ã¼ãå¼·å¶çã«validã«ãã # ããã©ã«ã: false # config.validate_on_invite = true # æå¾ æ¸ã¿ã®ã¦ã¼ã¶ã¼ãåã³invitedç¶æ ã«ãªã£ãå ´åã«ãæå¾ ã¡ã¼ã«ãåéä¿¡ãã # ããã©ã«ã: true # config.resend_invitation = false # æå¾ ããã¢ãã«ã®ã¯ã©ã¹å # nilã®å ´åã¯ããªã¢ã¼ãã£ãã¯é¢é£ã使ããã # ããã©ã«ã: nil # config.invited_by_class_name = 'User' # æå¾ ããã¢ãã«ã¸ã®å¤é¨ãã¼ # ããã©ã«ã: :invited_by_id # config.invited_by_foreign_key = :invited_by_id # ã«ã¦ã³ã¿ã¼ãã£ãã·ã¥ã®ã«ã©ã å # ããã©ã«ã: nil # config.invited_by_counter_cache = :invitations_count # æå¾ å¾èªåçã«ãã°ã¤ã³ç¶æ ã«ãªã # ããã©ã«ã: true # config.allow_insecure_sign_in_after_accept = false
ãã¥ã¼ãã«ã¹ã¿ãã¤ãºãã
ð± å ¨ã¦ã®ãã¥ã¼ã¯DeviseInvitable gemå ã«ããã±ã¼ã¸åããã¦ãããããã¥ã¼ãã«ã¹ã¿ãã¤ãºããå ´åã¯ãã¸ã§ãã¬ã¼ã¿ã¼ãå©ç¨ãã¦gemå ã®ãã¥ã¼ãã¢ããªå ã«ã³ãã¼ãã¦ãã
$ rails g devise_invitable:views invoke DeviseInvitable::Generators::MailerViewsGenerator exist app/views/devise/mailer create app/views/devise/mailer/invitation_instructions.html.erb create app/views/devise/mailer/invitation_instructions.text.erb invoke form_for create app/views/devise/invitations create app/views/devise/invitations/edit.html.erb create app/views/devise/invitations/new.html.erb
ð± ã¡ãªã¿ã«è¤æ°ã¢ãã«ãå©ç¨ããå ´åã¯Scopeãæå®ãããã¨ãå¯è½ã ãã
$ rails g devise_invitable:views users create app/views/users/mailer create app/views/users/mailer/invitation_instructions.html.erb create app/views/users/mailer/invitation_instructions.text.erb invoke form_for create app/views/users/invitations create app/views/users/invitations/edit.html.erb create app/views/users/invitations/new.html.erb
ã³ã³ããã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºãã
ð± ã³ã³ããã¼ã©ã¼ã¯DeviseInvitable gemå
ã«ããã±ã¼ã¸åããã¦ããããDevise::InvitationsController
ã¨ããã³ã³ããã¼ã©ã¼ã ãã
# https://github.com/scambra/devise_invitable/blob/master/app/controllers/devise/invitations_controller.rb class Devise::InvitationsController < DeviseController prepend_before_action :authenticate_inviter!, only: [:new, :create] prepend_before_action :has_invitations_left?, only: [:create] prepend_before_action :require_no_authentication, only: [:edit, :update, :destroy] prepend_before_action :resource_from_invitation_token, only: [:edit, :destroy] if respond_to? :helper_method helper_method :after_sign_in_path_for end # GET /resource/invitation/new def new self.resource = resource_class.new render :new end # POST /resource/invitation def create self.resource = invite_resource resource_invited = resource.errors.empty? yield resource if block_given? if resource_invited if is_flashing_format? && self.resource.invitation_sent_at set_flash_message :notice, :send_instructions, email: self.resource.email end if self.method(:after_invite_path_for).arity == 1 respond_with resource, location: after_invite_path_for(current_inviter) else respond_with resource, location: after_invite_path_for(current_inviter, resource) end else respond_with_navigational(resource) { render :new } end end # GET /resource/invitation/accept?invitation_token=abcdef def edit set_minimum_password_length resource.invitation_token = params[:invitation_token] render :edit end # PUT /resource/invitation def update raw_invitation_token = update_resource_params[:invitation_token] self.resource = accept_resource invitation_accepted = resource.errors.empty? yield resource if block_given? if invitation_accepted if resource.class.allow_insecure_sign_in_after_accept flash_message = resource.active_for_authentication? ? :updated : :updated_not_active set_flash_message :notice, flash_message if is_flashing_format? resource.after_database_authentication sign_in(resource_name, resource) respond_with resource, location: after_accept_path_for(resource) else set_flash_message :notice, :updated_not_active if is_flashing_format? respond_with resource, location: new_session_path(resource_name) end else resource.invitation_token = raw_invitation_token respond_with_navigational(resource) { render :edit } end end # GET /resource/invitation/remove?invitation_token=abcdef def destroy resource.destroy set_flash_message :notice, :invitation_removed if is_flashing_format? redirect_to after_sign_out_path_for(resource_name) end protected def invite_resource(&block) resource_class.invite!(invite_params, current_inviter, &block) end def accept_resource resource_class.accept_invitation!(update_resource_params) end def current_inviter authenticate_inviter! end def has_invitations_left? unless current_inviter.nil? || current_inviter.has_invitations_left? self.resource = resource_class.new set_flash_message :alert, :no_invitations_remaining if is_flashing_format? respond_with_navigational(resource) { render :new } end end def resource_from_invitation_token unless params[:invitation_token] && self.resource = resource_class.find_by_invitation_token(params[:invitation_token], true) set_flash_message(:alert, :invitation_token_invalid) if is_flashing_format? redirect_to after_sign_out_path_for(resource_name) end end def invite_params devise_parameter_sanitizer.sanitize(:invite) end def update_resource_params devise_parameter_sanitizer.sanitize(:accept_invitation) end def translation_scope 'devise.invitations' end end
ð± Deviseã¨éãã³ã³ããã¼ã©ã¼ã®generatorã¯åå¨ããªãã®ã§ãã«ã¹ã¿ãã¤ãºããéã¯èªåã§Devise::InvitationsController
ãç¶æ¿ããã³ã³ããã¼ã©ã¼ãä½æãã¦ãã
class Users::InvitationsController < Devise::InvitationsController def update # ã«ã¹ã¿ãã¤ãº end end
ð± èªåã®ã³ã³ããã¼ã©ã¼ãå©ç¨ããå ´åã¯ãã«ã¼ãã£ã³ã°ãå¤æ´ããå¿ è¦ããããã
# config/routes.rb # invitationsã³ã³ããã¼ã©ã¼ã«ã¯users/invitationsã使ã devise_for :users, controllers: { invitations: 'users/invitations' }
ð± ãã¨ã¯Deviseã¨åãããã«ãDevise::InvitationsController
ã®ã³ã¼ããè¦ãªããèªç±ã«ã«ã¹ã¿ãã¤ãºãã¦ãã
Strong Parameterãã«ã¹ã¿ãã¤ãºãã
ð± ãã¥ã¼ãã«ã¹ã¿ãã¤ãºããéã«ãã©ã¼ã ã«inputè¦ç´ ã追å ãããå ´åããããããã§ãDeviseInvitableã§ã¯Strong Parameterã§è¨±å¯ãããå±æ§ãããã©ã«ãã§æ±ºã¾ã£ã¦ããããããã¥ã¼ã ãã§ãªãStrong Parameterãå¤æ´ããå¿ è¦ããããã ã
ð± ããã©ã«ãã§è¨±å¯ããã¦ããå±æ§ã¯ä»¥ä¸ã®éãã ãã
ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | èå¥å | æ¦è¦ | 許å¯ããã¦ããå±æ§ |
---|---|---|---|
devise/invitations#create | :invite | æå¾ ã¡ã¼ã«éä¿¡ | |
devise/invitations#update | :accept_invitation | accept | invitation_token, password, password_confirmation |
ð± 許å¯ããå±æ§ã追å ãããå ´åã¯devise_parameter_sanitizer.permit
ã使ã£ã¦ãã
before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:accept_invitation, keys: [:first_name, :last_name, :phone]) end
ð± ãã詳ããç¥ãããå ´åã¯Deviseã® 021 Strong Parameterãã«ã¹ã¿ãã¤ãºãã ãåç §ãã¦ãã
I18nãã«ã¹ã¿ãã¤ãºãã
ð± Invitableã¢ã¸ã¥ã¼ã«ã¯flashã¡ãã»ã¼ã¸ã§I18nãå©ç¨ãã¦ãããããã®ããæ¥æ¬èªã®ãã±ã¼ã«ãã¡ã¤ã«ãç¨æãããã¨ã§flashã¡ãã»ã¼ã¸ãæ¥æ¬èªåã§ãããã
ð± æ¥æ¬èªã®ãã±ã¼ã«ãã¡ã¤ã«ã¯ Japanese locale file for DeviseInvitable · GitHub ã«ãããããã®ãã¡ã¤ã«ããã¦ã³ãã¼ããã¦locales/locales/devise_invitable.ja.yml
ã«ããã¦ãã
# locales/locales/devise_invitable.ja.yml ja: devise: failure: invited: 'ã¢ã«ã¦ã³ããä½æããã«ã¯ãä¿çä¸ã®æå¾ ãæ¿èªãã¦ãã ããã' invitations: send_instructions: 'æå¾ ã¡ã¼ã«ã%{email}ã«éä¿¡ããã¾ããã' invitation_token_invalid: 'æå¾ ã³ã¼ããä¸æ£ã§ãã' updated: 'ãã¹ã¯ã¼ããè¨å®ããã¾ãããã使ãã®ã¢ã«ã¦ã³ãã§ãã°ã¤ã³ã§ãã¾ãã' updated_not_active: 'ãã¹ã¯ã¼ããè¨å®ããã¾ããã' no_invitations_remaining: 'ãã以ä¸æå¾ ã§ãã¾ããã' invitation_removed: 'æå¾ ãåãæ¶ãã¾ããã' new: header: 'æå¾ ãã' submit_button: 'æå¾ ã¡ã¼ã«ãéã' edit: header: 'ãã¹ã¯ã¼ããè¨å®ãã' submit_button: 'ãã¹ã¯ã¼ããè¨å®ãã' mailer: invitation_instructions: subject: 'æå¾ ãæ¿èªããã«ã¯' hello: 'ããã«ã¡ã¯ã%{email}ãã' someone_invited_you: '%{url}ã«æå¾ ããã¾ããã以ä¸ã®ãªã³ã¯ããæ¿èªã§ãã¾ãã' accept: 'Accept invitation' accept: 'æå¾ ãæ¿èªãã' accept_until: 'ãã®æå¾ ã¯%{due_date}ã¾ã§æå¹ã§ãã' ignore: 'æå¾ ãæ¿èªããªãå ´åã¯ããã®ã¡ã¼ã«ãç¡è¦ãã¦ãã ããã<br />ããªãã®ã¢ã«ã¦ã³ãã¯ä¸è¨ã®ãªã³ã¯å ã«ã¢ã¯ã»ã¹ããã¹ã¯ã¼ããè¨å®ããã¾ã§ã¯ä½æããã¾ããã' time: formats: devise: mailer: invitation_instructions: accept_until_format: '%Yå¹´%mæ%dæ¥%Hæ%Må'
åè
056 Devise Security - ã¨ã³ã¿ã¼ãã©ã¤ãºãªã»ãã¥ãªãã£ã¼æ©è½ã追å ãã
ð± Devise Securityã¯Deviseã«ã¨ã³ã¿ã¼ãã©ã¤ãºãªã»ãã¥ãªãã£ã¼æ©è½ã追å ããããç§å¯ã®è³ªåã ã£ããããã¹ã¯ã¼ãã«æå¹æéãè¨ããããæ¨æºã®Deviseã§ã¯ã¾ããªããªãã»ãã¥ãªãã£ã¼è¦ä»¶ã«ã対å¿ã§ããããã«ãªããã
ð± ã¡ãªã¿ã«ãã®gemã®å ã«ãªã£ãDevise Security Extensionï¼devise_security_extensionï¼ã¨ããgemã¯ããã¡ã³ããã³ã¹ããã¦ããªãã®ã§ããã¡ãã®Devise Securityãå©ç¨ãã¦ãã
7ã¤ã®ã¢ã¸ã¥ã¼ã«
ð± Devise Securityã¯è¿½å ã®ã»ãã¥ãªãã£ã¼æ©è½ã以ä¸ã®7ã¤ã®ã¢ã¸ã¥ã¼ã«ã¨ãã¦æä¾ãããã
ã¢ã¸ã¥ã¼ã« | æ¦è¦ |
---|---|
:password_expirable | ä¸å®æéçµéããã¨ãã¹ã¯ã¼ããæéåãã«ãªããã¦ã¼ã¶ã¼ã¯å度ãã¹ã¯ã¼ããè¨å®ããªãã¨ãã°ã¤ã³ã§ããªããªãã |
:password_archivable | ãã¹ã¯ã¼ãå±¥æ´ãä¿åãã¦ãåããã¹ã¯ã¼ãã使ãããã«ããã ãã¹ã¯ã¼ãå±¥æ´ã¯ old_passwords ãã¼ãã«ã«ä¿åããã:password_expirable ã¨ã®ä½µç¨ãæ¨å¥¨ããã¦ããã |
:security_questionable | ç§å¯ã®è³ªåæ©è½ã |
:secure_validatable | email/passwordã«å¯¾ãã¦ãValidatableã¢ã¸ã¥ã¼ã«ããå¼·åãªããªãã¼ã·ã§ã³ãæä¾ããã |
:expirable | æå®æééã¢ã¯ãã£ãç¶æ ãç¶ãã¨ãã¦ã¼ã¶ã¼ã¢ã«ã¦ã³ããæéåãã«ããã |
:session_limitable | å¤éãã°ã¤ã³ç¦æ¢ã 1ã¢ã«ã¦ã³ãã§1ã»ãã·ã§ã³ããå©ç¨ã§ããªããªãã |
:paranoid_verification | èå¥ã³ã¼ãã®çºè¡æ©è½ã |
Devise Securityã使ã£ã¦ã¿ãã
ð± å®éã«ä½¿ã£ã¦ã¿ãããä»åã¯Password Expirableã¢ã¸ã¥ã¼ã«ãå©ç¨ãã¦ãä¸å®æéçµéããã¨ãã¹ã¯ã¼ããæéåãã«ãªãããã«ãããã
ð± ã¾ãã¯gemãinstallãããã
# Gemfile gem 'devise-security'
$ bundle install
ð± ã¸ã§ãã¬ã¼ã¿ã¼ãå®è¡ãã¦ãè¨å®ãã¡ã¤ã«ã¨ãã±ã¼ã«ãã¡ã¤ã«ãä½æãããã
$ rails g devise_security:install create config/initializers/devise-security.rb create config/locales/devise.security_extension.en.yml create config/locales/devise.security_extension.es.yml create config/locales/devise.security_extension.de.yml create config/locales/devise.security_extension.fr.yml create config/locales/devise.security_extension.it.yml create config/locales/devise.security_extension.ja.yml create config/locales/devise.security_extension.tr.yml
ð± è¨å®ãã¡ã¤ã«ã¯ãããªæãã ãã
# config/initializers/devise-security.rb # frozen_string_literal: true Devise.setup do |config| # ==> Security Extension # Configure security extension for devise # Should the password expire (e.g 3.months) # config.expire_password_after = false # Need 1 char of A-Z, a-z and 0-9 # config.password_complexity = { digit: 1, lower: 1, symbol: 1, upper: 1 } # How many passwords to keep in archive # config.password_archiving_count = 5 # Deny old passwords (true, false, number_of_old_passwords_to_check) # Examples: # config.deny_old_passwords = false # allow old passwords # config.deny_old_passwords = true # will deny all the old passwords # config.deny_old_passwords = 3 # will deny new passwords that matches with the last 3 passwords # config.deny_old_passwords = true # enable email validation for :secure_validatable. (true, false, validation_options) # dependency: see https://github.com/devise-security/devise-security/blob/master/README.md#e-mail-validation # config.email_validation = true # captcha integration for recover form # config.captcha_for_recover = true # captcha integration for sign up form # config.captcha_for_sign_up = true # captcha integration for sign in form # config.captcha_for_sign_in = true # captcha integration for unlock form # config.captcha_for_unlock = true # captcha integration for confirmation form # config.captcha_for_confirmation = true # Time period for account expiry from last_activity_at # config.expire_after = 90.days end
ð± æå¹ã«ãããã¢ã¸ã¥ã¼ã«ãdevise
ã¡ã½ããã§æå®ããããä»åã¯Password Expirableã¢ã¸ã¥ã¼ã«ãæå¹ã«ãããã
# app/models/user.rb class User < ApplicationRecord # :password_expirableã追å devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :password_expirable end
ð± Password Expirableã¢ã¸ã¥ã¼ã«ã§å¿ è¦ã«ãªãã«ã©ã ã追å ãããã
# ãã¤ã°ã¬ã¼ã·ã§ã³ãã¡ã¤ã« class AddPasswordExpirableColumnsToUsers < ActiveRecord::Migration[6.0] def change change_table :users do |t| t.datetime :password_changed_at end add_index :users, :password_changed_at end end
$ rails db:migrate
ð± ãã¹ã¯ã¼ãã®æå¹æéãè¨å®ããããä»åã¯åä½ç¢ºèªã®ããã«10ç§ã«è¨å®ãããã
# config/initializers/devise-security.rb - # config.expire_password_after = false + config.expire_password_after = 10.seconds
ð± ããã§å®äºã ããè¨å®ãåæ ãããããã«ãµã¼ãã¼ãåèµ·åãã¦ãã
ð± 10ç§å¾ ã£ã¦ãããã°ã¤ã³ãã¦ã¿ã¦ããããã¨ãã°ã¤ã³ã¨ã©ã¼ã«ãªã£ã¦ããããªæãã®ããã¹ã¯ã¼ããæéåãã«ãªãã¾ããããã¹ã¯ã¼ããæ´æ°ãã¦ãã ããããçãªã¡ãã»ã¼ã¸ã表示ããããã
ð± ã¦ã¼ã¶ã¼ã¯ãã®ç»é¢ã§æ°ãããã¹ã¯ã¼ããè¨å®ããã¾ã§ãã°ã¤ã³ã§ããªããªããã
ð± ããã§ä¸å®æéçµéã§ãã¹ã¯ã¼ããç¡å¹ã«ãªããã¨ã確èªã§ãããã
åè
- GitHub - devise-security/devise-security: A security extension for devise, meeting industrial standard security demands for web applications.
- devise-securityã使ã£ã¦ãããã»ãã¥ã¢ãªRailsã¢ããªãæ§ç¯ãã - Qiita
第13ç« Deviseå é¨ãç¥ã
057 Warden
ð± Wardenã¯Rackããã«ã¦ã§ã¢ãä»ãã¦èªè¨¼ãè¡ãä»çµã¿ãæä¾ããgemã ããWardenã使ãã¨Mountable Engineã¿ãããªä»ã®Rackã¢ããªããèªè¨¼ã«ã¢ã¯ã»ã¹ã§ããããã³ã³ããã¼ã©ã¼å±¤ã ãã§ãªãã«ã¼ãã£ã³ã°å±¤ãããèªè¨¼ã§ããããããã ã
ð± Deviseã¯å é¨çã«Wardenãå©ç¨ãã¦ããããä¾ãã°Deviseã«ã¯Userã¨ãAdminã¨ãè¤æ°ã®ã¢ãã«ã使ãããã®Scopeã¨ããæ©è½ãããã§ããï¼å®ã¯ãããWardenãæä¾ããæ©è½ãªãã ããããªã®ã§Wardenãç解ãããã¨ã§ãDeviseã«å¯¾ããç解ãããã«æ·±ã¾ããã
Wardenã使ã£ã¦ã¿ãã
ð± ã¾ãã¯Deviseã使ããã«Wardenã使ãèªè¨¼æ©è½ãå®è£ ãããã¨ã§ãWardenãã©ããªãµãã«ä½¿ãããããè¦ã¦ãããã
ð± ã¾ãã¯Wardenãã¤ã³ã¹ãã¼ã«ãããã
gem 'warden'
$ bundle install
ð± Strategyã¯ã©ã¹ãå®ç¾©ããããStrategyã¯èªè¨¼ã®ãã¸ãã¯ãç½®ãå ´æã§ãããã«å®éã®èªè¨¼ãè¡ãããã®ã³ã¼ããæ¸ãããä»åã¯emailã¨passwordã§ã®èªè¨¼ãå®è£ ããããï¼Wardenã®Strategyã¯Omniauthã®Strategyã¨ã¯å¥ç©ãªã®ã§æ³¨æï¼
# lib/strategies/password_strategy.rb class PasswordStrategy < ::Warden::Strategies::Base # å®éã®èªè¨¼ãè¡ããã¸ãã¯ã¯ããã«å®ç¾©ãã # èªè¨¼æåæã¯success!ããèªè¨¼å¤±ææã¯fail!ãå¼ã³åºã def authenticate! # Strategyã§ã¯paramsã«ã¢ã¯ã»ã¹ã§ãã user = User.find_by_email(params['email']) if user && user.authenticate(params['password']) # èªè¨¼æå # å¼æ°ã®userã«ã¯ã³ã³ããã¼ã©ã¼ããenv['warden'].userã§ã¢ã¯ã»ã¹ã§ããï¼ãããDeviseã§ããcurrent_userã«ãªãï¼ success! user else # èªè¨¼å¤±æ # å¼æ°ã®ã¡ãã»ã¼ã¸ã«ã¯ã³ã³ããã¼ã©ã¼ããenv['warden'].messageã§ã¢ã¯ã»ã¹ã§ãã fail! "Invalid email or password" end end end # PasswordStrategyã¯ã©ã¹ãwardenã®strategyã«è¿½å ãã Warden::Strategies.add(:password, PasswordStrategy)
ð± WardenãRackããã«ã¦ã§ã¢ã«è¿½å ãããã
# config/application.rb config.middleware.insert_after ActionDispatch::Flash, Warden::Manager do |manager| # å ç¨å®ç¾©ããStrategyãããã©ã«ãã®Strategyã¨ãã manager.default_strategies :password end
ð± ããã§ã³ã³ããã¼ã©ã¼ããwardenã«ã¢ã¯ã»ã¹ã§ããããã«ãªããã
# request.envãä»ãã¦wardenãåå¾ã§ãã warden = request.env['warden'] # Strategyãå®è¡ãã¦èªè¨¼ãã warden.authenticate! # èªè¨¼æ¸ã¿ãªãtrue warden.authenticated? #=> true # current_userãåå¾ warden.user #=> user # ãã°ã¢ã¦ããã warden.logout
ð± Wardenã¯ä¸åº¦èªè¨¼ãæåããã¨ãsessionã«ã¦ã¼ã¶ã¼æ å ±ãä¿åãã¦ããããããã®ããå度èªè¨¼ããéã«ã¯ãStrategyãå¼ã³åºãåã«sessionã«æ¢ã«ã¦ã¼ã¶ã¼ãä¿åããã¦ãããã©ããã確èªãã¦ãã¦ã¼ã¶ã¼ãããã°ãã¡ããå©ç¨ãã¦ããããã
ð± ã³ã³ããã¼ã©ã¼ã«éããRackç°å¢ãªãã©ãã§ãenv['warden']
ã§wardenã«ã¢ã¯ã»ã¹ã§ããã¨ããã®ããã¤ã³ãã ãã
åè
Strategyã¨ã¯ï¼
ð± Strategyã¯å®éã®èªè¨¼ãã¸ãã¯ãç½®ãå ´æã ãããããªæãã§å®ç¾©ãããã
# lib/strategies/password_strategy.rb class PasswordStrategy < ::Warden::Strategies::Base # å ·ä½çãªèªè¨¼ãã¸ãã¯ãå®ç¾©ãã # èªè¨¼æåæã¯success!ããèªè¨¼å¤±ææã¯fail!ãå¼ã³åºã def authenticate! # Strategyã§ã¯paramsã«ã¢ã¯ã»ã¹ã§ãã user = User.find_by_email(params['email']) if user && user.authenticate(params['password']) # èªè¨¼æå # å¼æ°ã®userã«ã¯ã³ã³ããã¼ã©ã¼ããenv['warden'].userã§ã¢ã¯ã»ã¹ã§ããï¼ãããcurrent_userã«ãªãï¼ success! user else # èªè¨¼å¤±æ # å¼æ°ã®ã¡ãã»ã¼ã¸ã«ã¯ã³ã³ããã¼ã©ã¼ããenv['warden'].messageã§ã¢ã¯ã»ã¹ã§ãã fail! "Invalid email or password" end end end
ð± Strategyã§ã¯ä»¥ä¸ã®ã¡ã½ãããå©ç¨ã§ãããã
ã¡ã½ãã | æ¦è¦ |
---|---|
success! | èªè¨¼æåãå¼æ°ã«ã¯userã渡ã |
fail! | èªè¨¼å¤±æãå¼æ°ã«ã¯ã¨ã©ã¼ã¡ãã»ã¼ã¸ã渡ã |
halt! | å¾ç¶ã®Strategyãå®è¡ããã«ãããã§èªè¨¼å¦çãåæ¢ãã |
redirect! | å¥ã®URLã«ãªãã¤ã¬ã¯ããã¦ãèªè¨¼å¦çãåæ¢ãã |
ð± authenticate!
以å¤ã«valid?
ã¨ããã¡ã½ãããå®ç¾©ãããã¨ãã§ããããvalid?
ã¯ã¬ã¼ãã¨ãã¦ã®å½¹å²ãæã£ã¦ãã¦ãtrueãè¿ãå ´åã ãauthenticate!
ãå®è¡ããããã
# lib/strategies/password_strategy.rb class PasswordStrategy < ::Warden::Strategies::Base # ã¬ã¼ãã¨ãã¦ã®å½¹å² # trueãè¿ãå ´åã ã`authenticate!`ãå®è¡ããã # ä½ãå®ç¾©ããªãã¨trueã«ãªãã常ã«å®è¡ããã def valid? params['email'] || params['password'] end def authenticate! user = User.find_by_email(params['email']) if user && user.authenticate(params['password']) success! user else fail "Invalid email or password" end end end
ð± Strategyã¯è¤æ°å®ç¾©ãããã¨ãã§ãã¦ãé çªã«å®è¡ãã¦ãããã¨ãå¯è½ã ãããã®ä¸ã®1ã¤ã§ãæåããããå ¨ã¦ã®æ¦ç¥ãéãããæ¦ç¥ãfail!ããã¾ã§å¼ã°ãããã
# PasswordStorategyã¨BasicStrategyãé ã«å®è¡ãã env['warden'].authenticate(:password, :basic)
ð± 以ä¸ãStrategyã®èª¬æã«ãªããããããããDeviseã«ã©ããªStrategyãåå¨ãããè¦ã¦ãããã
ð± Deviseã«ã¯2ã¤ã®Strategyãåå¨ãããã
ã¯ã©ã¹å | æ¦è¦ |
---|---|
Devise::Strategies::DatabaseAuthenticatable | emailã¨passwordã§èªè¨¼ã Database Authenticatableã¢ã¸ã¥ã¼ã«ã§å©ç¨ã |
Devise::Strategies::Rememberable | cookieã«ä¿åããtokenã§èªè¨¼ã Rememberableã¢ã¸ã¥ã¼ã«ã§å©ç¨ã |
ð± Devise::Strategies::DatabaseAuthenticatable
ã¯ãããªæãã ããã³ã¼ããèªãã¨email
ã¨password
ã§èªè¨¼ãã¦ããã¨ãããããã
# lib/devise/strategies/database_authenticatable.rb # frozen_string_literal: true require 'devise/strategies/authenticatable' module Devise module Strategies # Default strategy for signing in a user, based on their email and password in the database. class DatabaseAuthenticatable < Authenticatable def authenticate! resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash) hashed = false if validate(resource){ hashed = true; resource.valid_password?(password) } remember_me(resource) resource.after_database_authentication success!(resource) end # In paranoid mode, hash the password even when a resource doesn't exist for the given authentication key. # This is necessary to prevent enumeration attacks - e.g. the request is faster when a resource doesn't # exist in the database if the password hashing algorithm is not called. mapping.to.new.password = password if !hashed && Devise.paranoid unless resource Devise.paranoid ? fail(:invalid) : fail(:not_found_in_database) end end end end end Warden::Strategies.add(:database_authenticatable, Devise::Strategies::DatabaseAuthenticatable)
ð± Devise::Strategies::Rememberable
ã¯ãããªæãã ããCookieã®remember_token
ããuser
ããã·ãªã¢ã©ã¤ãºãã¦èªè¨¼ãã¦ãããCookieã«remember_token
ãåå¨ããå ´åã ãèªè¨¼ãå®è¡ããããã
# lib/devise/strategies/rememberable.rb # frozen_string_literal: true require 'devise/strategies/authenticatable' module Devise module Strategies # Remember the user through the remember token. This strategy is responsible # to verify whether there is a cookie with the remember token, and to # recreate the user from this cookie if it exists. Must be called *before* # authenticatable. class Rememberable < Authenticatable # A valid strategy for rememberable needs a remember token in the cookies. def valid? @remember_cookie = nil remember_cookie.present? end # To authenticate a user we deserialize the cookie and attempt finding # the record in the database. If the attempt fails, we pass to another # strategy handle the authentication. def authenticate! resource = mapping.to.serialize_from_cookie(*remember_cookie) unless resource cookies.delete(remember_key) return pass end if validate(resource) remember_me(resource) if extend_remember_me?(resource) resource.after_remembered success!(resource) end end # No need to clean up the CSRF when using rememberable. # In fact, cleaning it up here would be a bug because # rememberable is triggered on GET requests which means # we would render a page on first access with all csrf # tokens expired. def clean_up_csrf? false end private def extend_remember_me?(resource) resource.respond_to?(:extend_remember_period) && resource.extend_remember_period end def remember_me? true end def remember_key mapping.to.rememberable_options.fetch(:key, "remember_#{scope}_token") end def remember_cookie @remember_cookie ||= cookies.signed[remember_key] end end end end Warden::Strategies.add(:rememberable, Devise::Strategies::Rememberable)
ð± ãã®2ã¤ã®Strategyã¯åæã«ä½¿ããã¨ãã§ããããRememberableã¢ã¸ã¥ã¼ã«ã¨Database Authenticatableã¢ã¸ã¥ã¼ã«ãæå¹ãªå ´åãã¾ãDevise::Strategies::Rememberable
ã®èªè¨¼ãå®è¡ããã¦ã次ã«Devise::Strategies::DatabaseAuthenticatable
ã®èªè¨¼ãå®è¡ããããã
åè
Scopeã¨ã¯ï¼
ð± Scopeã使ãã¨UserãAdminãªã©ãè¤æ°ã®èªè¨¼ã¦ã¼ã¶ã¼ãå©ç¨ã§ããããã«ãªãããScopeæ¯ã«Sessionãåãã¦ç®¡çã§ããé©ç¨ããStrategyãåãããã¨ãã§ãããã ãï¼èªè¨¼ã¦ã¼ã¶ã¼ã¨ããèªãã¡ãã£ã¨ç´ãããããã©ãDeviseã§ããã¨UserãAdminã®ãããªèªè¨¼å¯¾è±¡ã®ã¢ãã«ã®ã¤ã¡ã¼ã¸ã ããï¼
ð± ããã©ã«ãã®Scopeã¯:default
ã§ãScopeãæå®ããã¦ããªãå ´åã¯å¸¸ã«:default
ã«ãªããã
ð± Scopeã¯ãããªæãã§å©ç¨ã§ãããã
èªè¨¼
# default Scope env['warden'].authenticated? # user Scope env['warden'].authenticated?(:user) # user Scope + password strategy env['warden'].authenticate(:password, scope: :user)
ã¦ã¼ã¶ã¼åå¾
# defaultã¦ã¼ã¶ã¼ env['warden'].user # userã¦ã¼ã¶ã¼ env['warden'].user(:user) # adminã¦ã¼ã¶ã¼ env['warden'].user(:admin)
ãã°ã¢ã¦ã
# å ¨ã¦ã¼ã¶ã¼ã®sessionãåé¤ env['warden'].logout # defaultã¦ã¼ã¶ã¼ã®sessionãåé¤ env['warden'].logout(:default) # userã¦ã¼ã¶ã¼ã®sessionãåé¤ env['warden'].logout(:user)
ð± Scopeã®è¨å®ã¯ãããªæãã ãã
use Warden::Manager do |manater| # userãããã©ã«ãScopeã«ãã manater.default_scope = :user # åScopeã«strategyãæå®ãã manater.scope_defaults :user, :strategies => [:password] manater.scope_defaults :api, :store => false, :strategies => [:api_token], :action => "unauthenticated_api" end
ð± Deviseã§ã¯Scopeã¯è¤æ°ã¢ãã«ãå©ç¨ããéãªããã«å©ç¨ããããã詳ãã㯠023 è¤æ°ã¢ãã«ãå©ç¨ãã ãåç §ãã¦ãã
åè
- Scopes · wardencommunity/warden Wiki · GitHub
- Authenticated session data · wardencommunity/warden Wiki · GitHub
åè
- Home · wardencommunity/warden Wiki · GitHub
- devise ãç¥ãã«ã¯ã¾ã warden ãç¥ããè¯ã - vimtaku blog
- Warden ã使ã£ãèªè¨¼ã®ãµã³ãã«
- warden ã®ã³ã¼ããªã¼ãã£ã³ã° - ogidowã®æ¥è¨
058 Rails Engine
ð¦ð» Deviseã£ã¦ã³ã³ããã¼ã©ã¼ããã¥ã¼ãä½æãã¦ãªãç¶æ ã§ããã°ã¤ã³æ©è½ã¨ã使ããããï¼ããã£ã¦ãªãã§ï¼
ð± ããã¯DeviseãRails Engineï¼ä»¥ä¸Engineï¼ã¨ããä»çµã¿ã使ã£ã¦ãããã ããEngineã使ãã¨ãã¹ãã¨ãªãRailsã¢ããªã±ã¼ã·ã§ã³ã«å¯¾ãã¦ãgemå½¢å¼ã§å¥ã®Railsã¢ããªã±ã¼ã·ã§ã³ã丸ãã¨æä¾ã§ãããã ãDeviseã§ã¯ã³ã³ããã¼ã©ã¼ã»ãã¥ã¼ã»ãã«ãã¼ã»ã¡ã¼ã©ã¼ãEngineã使ã£ã¦æä¾ãã¦ãããã
ð± ãã¹ãã¢ããªã±ã¼ã·ã§ã³ï¼èªåã®Railsã¢ããªã±ã¼ã·ã§ã³ï¼ã§ã¯Rails::Application
ãç¶æ¿ããã¯ã©ã¹ãå®ç¾©ãã¦ãããããconfig/application.rb
ã«å®ç¾©ããã¦ãã¦ãããã§å®ç¾©ããã¦ããã¯ã©ã¹ããã¹ãã¢ããªã±ã¼ã·ã§ã³æ¬ä½ã«ãªããã
# conig/application.rb module DemoApp class Application < Rails::Application # ...çç¥... end end
ð± ã³ã¬ã«å¯¾ãã¦Engineã§ã¯Rails::Engine
ãç¶æ¿ããã¯ã©ã¹ãå®ç¾©ãããã以ä¸ã¯Deviseã®ä¾ã ãã
# lib/devise/rails.rb module Devise class Engine < ::Rails::Engine # ...çç¥... end end
ð± ãã®2ã¤ã®æ§é ã¯ä¼¼ã¦ãããããå®éApplicationã¨Engineã¯å°ããªéããé¤ãã°ã»ã¨ãã©åããã®ã ããã¤ã¾ãDevise gemã®ä¸ã«ãå¥ã®Railsã¢ããªã±ã¼ã·ã§ã³ããã£ã¦ãããããã¹ãã¢ããªã±ã¼ã·ã§ã³ããå©ç¨ããæãã«ãªããã ãã
2ã¤ã®Engine
ð± Engineã¯2ã¤ã®ã¿ã¤ããåå¨ããããisolate_namespace
ã¡ã½ããã使ã£ã¦ãããã®ã¨ã使ã£ã¦ããªããã®ãåè
ã¯mountMountable Engineãå¾è
ã¯Full Engineã¨å¼ã°ãããã¨ããããã
isolate_namespaceããã®Engine
ð± isolate_namespace
ã使ãã¨Engineã®åå空éããã¹ãããåãåãããã¨ãã§ãããã¹ãã¨çãªEngineã«ããäºãã§ããããã³ã³ããã¼ã©ã¼åã»ã¢ãã«åã»ãã¼ãã«åã«åå空éãããããããã¹ãã¢ããªã±ã¼ã·ã§ã³ã¨ååãè¡çªãããã¨ããªããªããã ãä¾ãã°Engine1
ã¨ããã¢ããªã±ã¼ã·ã§ã³ã®Article
ã¢ãã«ã¯Engine1::Article
ã¨ãªããã
ð± isolate_namespace
ã使ã£ã¦ä½ãããEngineã¯Rackã¢ããªã¨ãã¦mountå¯è½ã ãããããªæãã§ãã¹ãå´ããmountã¡ã½ããã使ããã¨ã§ãEngineã«ã¢ã¯ã»ã¹ã§ããããã«ãªããã
# config/routes.rb # http://localhost:3000/engine1 ã§Engineã«ã¢ã¯ã»ã¹å¯è½ã«ãªã mount Engine1::Engine, at: "/engine1"
ð± ãã¹ãå´ã®ã¢ããªã±ã¼ã·ã§ã³ã¨åãã¦ç®¡çãããå ´åãä¾ãã°ç®¡çç»é¢ãä½æããå ´åãªããã«å©ç¨ããããã
ð± isolate_namespace
ããã®Engineãä½ãã«ã¯ä»¥ä¸ã®ã³ãã³ããå®è¡ããã°OKã ãã
$ rails plugin new engine1 --mountable create create README.md create Rakefile create engine1.gemspec create MIT-LICENSE create .gitignore create Gemfile create app create app/controllers/engine1/application_controller.rb create app/helpers/engine1/application_helper.rb create app/jobs/engine1/application_job.rb create app/mailers/engine1/application_mailer.rb create app/models/engine1/application_record.rb create app/views/layouts/engine1/application.html.erb create app/assets/images/engine1 create app/assets/images/engine1/.keep create config/routes.rb create lib/engine1.rb create lib/tasks/engine1_tasks.rake create lib/engine1/version.rb create lib/engine1/engine.rb create app/assets/config/engine1_manifest.js create app/assets/stylesheets/engine1/application.css create bin/rails create test/test_helper.rb create test/engine1_test.rb append Rakefile create test/integration/navigation_test.rb vendor_app test/dummy
ð± ãããªæãã§isolate_namespace
ãå©ç¨ããEngineãä½æããããã
# engine1/lib/engine1/engine.rb module Engine1 class Engine < ::Rails::Engine isolate_namespace Engine1 end end
ð± 代表çãªgemã¨ãã¦ã¯ãrails_adminãisolate_namespace
ããã®Engineã使ã£ã¦ãããã
# ...çç¥... module RailsAdmin class Engine < Rails::Engine isolate_namespace RailsAdmin # ...çç¥... end end
åè
isolate_namespaceãªãã®Engine
ð± isolate_namespace
ã使ããªãå ´åã¯åå空éãªãã«ãªããããã®ãããã¹ãå´ã¨ååãè¡çªããå¯è½æ§ãããã®ã§å½åã«ã¯æ³¨æãã¦ãã
ð± ã«ã¼ãã£ã³ã°ã«é¢ãã¦ããããããã¹ãå´ã§mountããå¿ è¦ã¯ãªãã¦ãgemãinstallããã°ãã®ã¾ã¾ãã¹ãã¢ããªã±ã¼ã·ã§ã³ããEngineã«ã¢ã¯ã»ã¹ã§ãããã
ð± isolate_namespace
ããã®Engineãä½ãã«ã¯ä»¥ä¸ã®ã³ãã³ããå®è¡ããã°OKã ãã
$ rails plugin new engine2 --full create create README.md create Rakefile create engine2.gemspec create MIT-LICENSE create .gitignore create Gemfile create app/models create app/models/.keep create app/controllers create app/controllers/.keep create app/mailers create app/mailers/.keep create app/assets/images/engine2 create app/assets/images/engine2/.keep create app/helpers create app/helpers/.keep create app/views create app/views/.keep create config/routes.rb create lib/engine2.rb create lib/tasks/engine2_tasks.rake create lib/engine2/version.rb create lib/engine2/engine.rb create app/assets/config/engine2_manifest.js create app/assets/stylesheets/engine2 create app/assets/stylesheets/engine2/.keep create bin/rails create test/test_helper.rb create test/engine2_test.rb append Rakefile create test/integration/navigation_test.rb vendor_app test/dummy
ð± isolate_namespace
ãªãã®Engineãç¨æããããã
# engine2/lib/engine2/engine.rb module Engine2 class Engine < ::Rails::Engine end end
ð± Deviseã¯isolate_namespace
ãªãã®Engineã ããï¼ãã ãã³ã³ããã¼ã©ã¼ã«åå空éãç¨æããã¦ããããã«ã¼ãã£ã³ã°ãdevise_forã¡ã½ããã§å¶å¾¡ãããã¨ãMountable Engineçãªåä½ãããï¼
Deviseã®Engine
ð± Deviseã§ã©ããªæãã§Engineãå©ç¨ããã¦ããããå®éã®Deviseã®ã³ã¼ããè¦ãªãã解説ãã¦ããããDeviseã®ã³ã¼ã㯠https://github.com/heartcombo/devise ããè¦ããã¨ãã§ãããã
ð± Devise gemã®ããã¸ã§ã¯ãã«ã¼ãã¯ãããªæãã«ãªã£ã¦ãããã
app/ bin/ config/ gemfiles/ guides/ lib/ test/ Gemfile.lock ISSUE_TEMPLATE.md MIT-LICENSE README.md Rakefile devise.png devise.gemspec CODE_OF_CONDUCT.md CONTRIBUTING.md Gemfile CHANGELOG.md .git/ .gitignore .travis.yml .yardopts
ð± ä¸è¬çãªgemã®ãã£ã¬ã¯ããªæ§æã¨ãããªã«å¤ãããªãããã§ã1ç¹ã ã大ããªéããããããgemã®ä¸ã«app
ãã£ã¬ã¯ããªãåå¨ãããã ãapp
ãã£ã¬ã¯ããªã®ä¸ãè¦ã¦ãããã
appãã£ã¬ã¯ããª
ð± Railsã¢ããªã±ã¼ã·ã§ã³ã®appãã£ã¬ã¯ããªã¨åãããã«ãDeviseã®appãã£ã¬ã¯ããªã®ä¸ã«ã¯ã³ã³ããã¼ã©ã¼ããã¥ã¼ãç½®ããã¦ãããã
controllers/ helpers/ mailers/ views/
ð± controllersãã£ã¬ã¯ããªãè¦ããã
devise/ devise_controller.rb
ð± devise_controller.rb
ã¨deivse
ãã£ã¬ã¯ããªãããããdevise_controller.rb
ã®DeviseController
ã¯Deviseã®å
¨ã³ã³ããã¼ã©ã¼ã®è¦ªã«ãªãã¯ã©ã¹ã ãã
# app/controllers/devise_controller.rb class DeviseController < Devise.parent_controller.constantize # ...çç¥... end
ð± devise
ãã£ã¬ã¯ããªã®ä¸ã«ã¯ãåãã¡ããã¹ãã¢ããªããå®éã«å©ç¨ããã³ã³ããã¼ã©ã¼6ã¤ãç½®ããã¦ãããã
confirmations_controller.rb omniauth_callbacks_controller.rb passwords_controller.rb registrations_controller.rb sessions_controller.rb unlocks_controller.rb
ð± confirmations_controller.rb
ãè¦ã¦ã¿ããã
# app/controllers/devise/confirmations_controller.rb class Devise::ConfirmationsController < DeviseController # GET /resource/confirmation/new def new self.resource = resource_class.new end # POST /resource/confirmation def create self.resource = resource_class.send_confirmation_instructions(resource_params) yield resource if block_given? if successfully_sent?(resource) respond_with({}, location: after_resending_confirmation_instructions_path_for(resource_name)) else respond_with(resource) end end # GET /resource/confirmation?confirmation_token=abcdef def show self.resource = resource_class.confirm_by_token(params[:confirmation_token]) yield resource if block_given? if resource.errors.empty? set_flash_message!(:notice, :confirmed) respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) } else respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new } end end protected # The path used after resending confirmation instructions. def after_resending_confirmation_instructions_path_for(resource_name) is_navigational_format? ? new_session_path(resource_name) : '/' end # The path used after confirmation. def after_confirmation_path_for(resource_name, resource) if signed_in?(resource_name) signed_in_root_path(resource) else new_session_path(resource_name) end end def translation_scope 'devise.confirmations' end end
ð± DeviseController
ãç¶æ¿ããDevise::ConfirmationsController
ãå®ç¾©ããã¦ãããããã®Devise::ConfirmationsController
ã¯Confirmableã¢ã¸ã¥ã¼ã«ã§å©ç¨ããã³ã³ããã¼ã©ã¼ã§ãåã¢ã¯ã·ã§ã³ã¯ãããªæãã ãã
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/confirmation | devise/confirmations#show | confirmãã¡ã¼ã«ã®ãªã³ã¯å ã¯ãããã¯ã¨ãªãã©ã¡ã¼ã¿ã¼ã®confirmation_tokenãä¸è´ããªãã¨ã¢ã¯ã»ã¹ã§ããªãã |
GET | /users/confirmation/new | devise/confirmations#new | confirmæ示ã¡ã¼ã«åéä¿¡ç»é¢ã |
POST | /users/confirmation | devise/confirmations#create | confirmæ示ã¡ã¼ã«éä¿¡ã |
ð± controllersãã£ã¬ã¯ããªã¨åãããã«ãviewsãã£ã¬ã¯ããªãhelpersãã£ã¬ã¯ããªãmailersãã£ã¬ã¯ããªã«ããã®Engineã§å©ç¨ããã³ã¼ããç½®ããã¦ããããEngineã®ä»çµã¿ã使ã£ã¦ããã¹ãã¢ããªã±ã¼ã·ã§ã³ãããã®appãã£ã¬ã¯ããªãå©ç¨ãããã¨ã«ãªããã ãã
Engineã¯ã©ã¹
ð± Engineãç¨ããgemã¯ãappãã£ã¬ã¯ããªä»¥å¤ã«ãã1ã¤ãä¸è¬çãªgemã¨éãç¹ãããããRails::Engine
ã¯ã©ã¹ãç¶æ¿ããEngine
ã¯ã©ã¹ãå®ç¾©ããã¦ãããã ãRails::Engine
ãç¶æ¿ããã¯ã©ã¹ã§ã¯ããã¹ãã¢ããªã±ã¼ã·ã§ã³ã«ã¢ã¯ã»ã¹ããããEngineã®åæåãè¡ã£ããã§ãããã
ð± Deviseã§ã¯lib/devise/rails.rb
ã§å®ç¾©ããã¦ããããããã§ã¯current_userãªã©ã®ãã«ãã¼ã¡ã½ããã®è¿½å ãè¡ã£ã¦ãããã
# lib/devise/rails.rb # frozen_string_literal: true require 'devise/rails/routes' require 'devise/rails/warden_compat' module Devise # Rails::Engineãç¶æ¿ãããDevise::Engineãå®ç¾© # Rails::Engineãç¶æ¿ããã¨ãEngineããããã¨ãgemããApplicationã«éç¥ããã # ããã§ã¯ãã¹ãã¢ããªã±ã¼ã·ã§ã³ã«ã¢ã¯ã»ã¹ããããEngineã®åæåãè¡ã£ããã§ãã class Engine < ::Rails::Engine config.devise = Devise # Warden::Managerãããã«ã¦ã§ã¢ã«è¿½å config.app_middleware.use Warden::Manager do |config| Devise.warden_config = config end # eager_loadåã«ãã¹ãã¢ããªã±ã¼ã·ã§ã³ã®ã«ã¼ãã£ã³ã°ããªãã¼ã config.before_eager_load do |app| app.reload_routes! if Devise.reload_routes end # current_userãªã©ã®ãã«ãã¼ã¡ã½ããã追å initializer "devise.url_helpers" do Devise.include_helpers(Devise::Controllers) end # Omniauthã®è¨å® initializer "devise.omniauth", after: :load_config_initializers, before: :build_middleware_stack do |app| Devise.omniauth_configs.each do |provider, config| app.middleware.use config.strategy_class, *config.args do |strategy| config.strategy = strategy end end if Devise.omniauth_configs.any? Devise.include_helpers(Devise::OmniAuth) end end # secret_keyã®è¨å® initializer "devise.secret_key" do |app| Devise.secret_key ||= Devise::SecretKeyFinder.new(app).find Devise.token_generator ||= if secret_key = Devise.secret_key Devise::TokenGenerator.new( ActiveSupport::CachingKeyGenerator.new(ActiveSupport::KeyGenerator.new(secret_key)) ) end end end end
åè
059 Deviseã³ã¼ããªã¼ãã£ã³ã°
ð± Deviseã¯ã¬ã¼ã«ã«ä¹ã£ã¦ããå ´åã¯çµæ§ç°¡åã«ã«ã¹ã¿ãã¤ãºã§ããããã§ãã¬ã¼ã«ããå¤ããå ´åãä¾ãã°ã³ã³ããã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºãããå ´åãªã©ã«ã¯ãDeviseã®ã½ã¼ã¹ã³ã¼ããèªãå¿ è¦ãã§ã¦ãããã ããªã®ã§Deviseãã©ããªãã£ã¬ã¯ããªæ§æã«ãªã£ã¦ãã¦ãã©ããªã³ã¼ããç½®ããã¦ããããç°¡åã«ã§ãç解ãã¦ããã¨ãã«ã¹ã¿ãã¤ãºã®å©ãã«ãªããã
ð± Deviseã®ããã¸ã§ã¯ãã«ã¼ãã¯ãããªæãã ãã
app/ bin/ config/ gemfiles/ guides/ lib/ test/ Gemfile.lock ISSUE_TEMPLATE.md MIT-LICENSE README.md Rakefile devise.png devise.gemspec CODE_OF_CONDUCT.md CONTRIBUTING.md Gemfile CHANGELOG.md .git/ .gitignore .travis.yml .yardopts
ð± ãã®ä¸ã§ãã¨ããã大äºãªã®ãapp/
ã¨lib/
ã ããé ã«èª¬æãã¦ãããã
app/
ð± appãã£ã¬ã¯ããªã«ã¯ã³ã³ããã¼ã©ã¼ããã¥ã¼ãç½®ããã¦ãã¦ããããã¯Rails Engineã¨ãã¦ç¬ç«ããã¢ããªã±ã¼ã·ã§ã³ã§ãããã®ããã«æ©è½ãããã
controllers/ helpers/ mailers/ views/
app/controllers/
ð± controllersãã£ã¬ã¯ããªé ä¸ã¯ãããªæãã ãã
$ tree app/controllers app/controllers âââ devise â  âââ confirmations_controller.rb # Confirmableã¢ã¸ã¥ã¼ã«ç¨ã®ã³ã³ããã¼ã©ã¼ â  âââ omniauth_callbacks_controller.rb # Omniauthableã¢ã¸ã¥ã¼ã«ç¨ã®ã³ã³ããã¼ã©ã¼ â  âââ passwords_controller.rb # Recoverableã¢ã¸ã¥ã¼ã«ç¨ã®ã³ã³ããã¼ã©ã¼ â  âââ registrations_controller.rb # Registerableã¢ã¸ã¥ã¼ã«ç¨ã®ã³ã³ããã¼ã©ã¼ â  âââ sessions_controller.rb # Database Authenticatableã¢ã¸ã¥ã¼ã«ç¨ã®ã³ã³ããã¼ã©ã¼ â  âââ unlocks_controller.rb # Lockableã¢ã¸ã¥ã¼ã«ç¨ã®ã³ã³ããã¼ã©ã¼ âââ devise_controller.rb # 親ã³ã³ããã¼ã©ã¼ 1 directory, 7 files
ð± devise_controller.rb
ã®DeviseController
ã¯Deviseã®åã³ã³ããã¼ã©ã¼ã®è¦ªã¨ãªãã¯ã©ã¹ã§ãã³ã³ããã¼ã©ã¼ã«å
±éã®å¦çã¯ããã«ç½®ããã¦ãããã
# app/controllers/ # frozen_string_literal: true # All Devise controllers are inherited from here. class DeviseController < Devise.parent_controller.constantize include Devise::Controllers::ScopedViews if respond_to?(:helper) helper DeviseHelper end if respond_to?(:helper_method) helpers = %w(resource scope_name resource_name signed_in_resource resource_class resource_params devise_mapping) helper_method(*helpers) end prepend_before_action :assert_is_devise_resource! respond_to :html if mimes_for_respond_to.empty? # Override prefixes to consider the scoped view. # Notice we need to check for the request due to a bug in # Action Controller tests that forces _prefixes to be # loaded before even having a request object. # # This method should be public as it is in ActionPack # itself. Changing its visibility may break other gems. def _prefixes #:nodoc: @_prefixes ||= if self.class.scoped_views? && request && devise_mapping ["#{devise_mapping.scoped_path}/#{controller_name}"] + super else super end end protected # Gets the actual resource stored in the instance variable def resource instance_variable_get(:"@#{resource_name}") end # Proxy to devise map name def resource_name devise_mapping.name end alias :scope_name :resource_name # Proxy to devise map class def resource_class devise_mapping.to end # Returns a signed in resource from session (if one exists) def signed_in_resource warden.authenticate(scope: resource_name) end # Attempt to find the mapped route for devise based on request path def devise_mapping @devise_mapping ||= request.env["devise.mapping"] end # Checks whether it's a devise mapped resource or not. def assert_is_devise_resource! #:nodoc: unknown_action! <<-MESSAGE unless devise_mapping Could not find devise mapping for path #{request.fullpath.inspect}. This may happen for two reasons: 1) You forgot to wrap your route inside the scope block. For example: devise_scope :user do get "/some/route" => "some_devise_controller" end 2) You are testing a Devise controller bypassing the router. If so, you can explicitly tell Devise which mapping to use: @request.env["devise.mapping"] = Devise.mappings[:user] MESSAGE end # Returns real navigational formats which are supported by Rails def navigational_formats @navigational_formats ||= Devise.navigational_formats.select { |format| Mime::EXTENSION_LOOKUP[format.to_s] } end def unknown_action!(msg) logger.debug "[Devise] #{msg}" if logger raise AbstractController::ActionNotFound, msg end # Sets the resource creating an instance variable def resource=(new_resource) instance_variable_set(:"@#{resource_name}", new_resource) end # Helper for use in before_actions where no authentication is required. # # Example: # before_action :require_no_authentication, only: :new def require_no_authentication assert_is_devise_resource! return unless is_navigational_format? no_input = devise_mapping.no_input_strategies authenticated = if no_input.present? args = no_input.dup.push scope: resource_name warden.authenticate?(*args) else warden.authenticated?(resource_name) end if authenticated && resource = warden.user(resource_name) set_flash_message(:alert, 'already_authenticated', scope: 'devise.failure') redirect_to after_sign_in_path_for(resource) end end # Helper for use after calling send_*_instructions methods on a resource. # If we are in paranoid mode, we always act as if the resource was valid # and instructions were sent. def successfully_sent?(resource) notice = if Devise.paranoid resource.errors.clear :send_paranoid_instructions elsif resource.errors.empty? :send_instructions end if notice set_flash_message! :notice, notice true end end # Sets the flash message with :key, using I18n. By default you are able # to set up your messages using specific resource scope, and if no message is # found we look to the default scope. Set the "now" options key to a true # value to populate the flash.now hash in lieu of the default flash hash (so # the flash message will be available to the current action instead of the # next action). # Example (i18n locale file): # # en: # devise: # passwords: # #default_scope_messages - only if resource_scope is not found # user: # #resource_scope_messages # # Please refer to README or en.yml locale file to check what messages are # available. def set_flash_message(key, kind, options = {}) message = find_message(kind, options) if options[:now] flash.now[key] = message if message.present? else flash[key] = message if message.present? end end # Sets flash message if is_flashing_format? equals true def set_flash_message!(key, kind, options = {}) if is_flashing_format? set_flash_message(key, kind, options) end end # Sets minimum password length to show to user def set_minimum_password_length if devise_mapping.validatable? @minimum_password_length = resource_class.password_length.min end end def devise_i18n_options(options) options end # Get message for given def find_message(kind, options = {}) options[:scope] ||= translation_scope options[:default] = Array(options[:default]).unshift(kind.to_sym) options[:resource_name] = resource_name options = devise_i18n_options(options) I18n.t("#{options[:resource_name]}.#{kind}", **options) end # Controllers inheriting DeviseController are advised to override this # method so that other controllers inheriting from them would use # existing translations. def translation_scope "devise.#{controller_name}" end def clean_up_passwords(object) object.clean_up_passwords if object.respond_to?(:clean_up_passwords) end def respond_with_navigational(*args, &block) respond_with(*args) do |format| format.any(*navigational_formats, &block) end end def resource_params params.fetch(resource_name, {}) end ActiveSupport.run_load_hooks(:devise_controller, self) end
ð± deviseãã£ã¬ã¯ããªé
ä¸ã«å®éã«å©ç¨ããã³ã³ããã¼ã©ã¼ãç½®ããã¦ããããä¾ãã°sessions_controller.rb
ã®Devise::SessionsController
ã¯Database Authenticableã¢ã¸ã¥ã¼ã«ã§å©ç¨ããã³ã³ããã¼ã©ã¼ã§ããã°ã¤ã³/ãã°ã¢ã¦ãã®ã¢ã¯ã·ã§ã³ãå®ç¾©ããã¦ãããããã°ã¤ã³/ãã°ã¢ã¦ãã®ã¢ã¯ã·ã§ã³ãã«ã¹ã¿ãã¤ãºãããå ´åãªããã¯ãã®ã³ã³ããã¼ã©ã¼ãåèã«ããªãããã«ã¹ã¿ã ã³ã³ããã¼ã©ã¼ãä¿®æ£ãã¦ãããã¨ã«ãªããã詳ãã㯠020 ã³ã³ããã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºãã ãåç
§ãã¦ãã
# app/controllers/sessions_controller.rb # frozen_string_literal: true class Devise::SessionsController < DeviseController prepend_before_action :require_no_authentication, only: [:new, :create] prepend_before_action :allow_params_authentication!, only: :create prepend_before_action :verify_signed_out_user, only: :destroy prepend_before_action(only: [:create, :destroy]) { request.env["devise.skip_timeout"] = true } # GET /resource/sign_in def new self.resource = resource_class.new(sign_in_params) clean_up_passwords(resource) yield resource if block_given? respond_with(resource, serialize_options(resource)) end # POST /resource/sign_in def create self.resource = warden.authenticate!(auth_options) set_flash_message!(:notice, :signed_in) sign_in(resource_name, resource) yield resource if block_given? respond_with resource, location: after_sign_in_path_for(resource) end # DELETE /resource/sign_out def destroy signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)) set_flash_message! :notice, :signed_out if signed_out yield if block_given? respond_to_on_destroy end protected def sign_in_params devise_parameter_sanitizer.sanitize(:sign_in) end def serialize_options(resource) methods = resource_class.authentication_keys.dup methods = methods.keys if methods.is_a?(Hash) methods << :password if resource.respond_to?(:password) { methods: methods, only: [:password] } end def auth_options { scope: resource_name, recall: "#{controller_path}#new" } end def translation_scope 'devise.sessions' end private # Check if there is no signed in user before doing the sign out. # # If there is no signed in user, it will set the flash message and redirect # to the after_sign_out path. def verify_signed_out_user if all_signed_out? set_flash_message! :notice, :already_signed_out respond_to_on_destroy end end def all_signed_out? users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) } users.all?(&:blank?) end def respond_to_on_destroy # We actually need to hardcode this as Rails default responder doesn't # support returning empty response on GET request respond_to do |format| format.all { head :no_content } format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) } end end end
app/mailers/
ð± mailersãã£ã¬ã¯ããªã«ã¯mailer.rb
ãããã ãã ãã
$ tree app/mailers app/mailers âââ devise âââ mailer.rb 1 directory, 1 file
ð± ããã§ã¯Deivseã®ã¡ã¼ã©ã¼ã§ããDevise::Mailer
ã¯ã©ã¹ãå®ç¾©ããã¦ãããããã¡ãã¯ã³ã³ããã¼ã©ã¼ã¨ã¯éããã¢ã¸ã¥ã¼ã«æ¯ã«åããã¦ããããã§ã¯ãªãã5ã¤ã®ã¡ã¼ã«ãå
¨ã¦ãã®ã¯ã©ã¹ã«å®ç¾©ããã¦ããããåã¡ã¼ã«ã¯tokenãç¨æãããã©ãããéããããã§ããã¨ã¯å
±éã®å¦çã«ãªã£ã¦ãããã
# app/mailers/devise/mailer.rb # frozen_string_literal: true if defined?(ActionMailer) class Devise::Mailer < Devise.parent_mailer.constantize include Devise::Mailers::Helpers def confirmation_instructions(record, token, opts = {}) @token = token devise_mail(record, :confirmation_instructions, opts) end def reset_password_instructions(record, token, opts = {}) @token = token devise_mail(record, :reset_password_instructions, opts) end def unlock_instructions(record, token, opts = {}) @token = token devise_mail(record, :unlock_instructions, opts) end def email_changed(record, opts = {}) devise_mail(record, :email_changed, opts) end def password_change(record, opts = {}) devise_mail(record, :password_change, opts) end end end
app/views/
ð± viewsãã£ã¬ã¯ããªã¯ãããªæãã ããã³ã³ããã¼ã©ã¼ã¨ã¡ã¼ã©ã¼ã®ãã¥ã¼ãç½®ããã¦ãããã
$ tree app/views app/views âââ devise âââ confirmations â  âââ new.html.erb âââ mailer â  âââ confirmation_instructions.html.erb â  âââ email_changed.html.erb â  âââ password_change.html.erb â  âââ reset_password_instructions.html.erb â  âââ unlock_instructions.html.erb âââ passwords â  âââ edit.html.erb â  âââ new.html.erb âââ registrations â  âââ edit.html.erb â  âââ new.html.erb âââ sessions â  âââ new.html.erb âââ shared â  âââ _error_messages.html.erb â  âââ _links.html.erb âââ unlocks âââ new.html.erb 8 directories, 14 files
ð± ãã®ãã¥ã¼ã¯$ rails g devise:views
ã³ãã³ãã§ã³ãã¼ãããã¥ã¼ã¨åããã®ã ãããã¥ã¼ãã¢ããªå
ã«ã³ãã¼ããå ´åã¯ã¢ããªå
ã®ãã¥ã¼ã使ããã³ãã¼ããªãå ´åã¯ãã¡ãã®gemå
ã®ãã¥ã¼ãå©ç¨ãããã¨ã«ãªããã
ð± shared
ãã£ã¬ã¯ããªã«ã¯ãã¼ã·ã£ã«ãç½®ããã¦ãããã_error_messages.html.erb
ã¯ããªãã¼ã·ã§ã³ã¨ã©ã¼ã®è¡¨ç¤ºã ãã
# devise/app/views/devise/shared/_error_messages.html.erb <% if resource.errors.any? %> <div id="error_explanation"> <h2> <%= I18n.t("errors.messages.not_saved", count: resource.errors.count, resource: resource.class.model_name.human.downcase) %> </h2> <ul> <% resource.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %>
ð± _links.html.erb
ã¯ãµã¤ã³ã¢ããããã°ã¤ã³ãªã©ã®ãªã³ã¯ãéãããã®ã ããç¾å¨ã®pathãæå¹ãªã¢ã¸ã¥ã¼ã«ã«ãã£ã¦è¡¨ç¤ºãããªã³ã¯å¤ãã¦ãããã
# devise/app/views/devise/shared/_links.html.erb <%- if controller_name != 'sessions' %> <%= link_to "Log in", new_session_path(resource_name) %><br /> <% end %> <%- if devise_mapping.registerable? && controller_name != 'registrations' %> <%= link_to "Sign up", new_registration_path(resource_name) %><br /> <% end %> <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> <%= link_to "Forgot your password?", new_password_path(resource_name) %><br /> <% end %> <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br /> <% end %> <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br /> <% end %> <%- if devise_mapping.omniauthable? %> <%- resource_class.omniauth_providers.each do |provider| %> <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br /> <% end %> <% end %>
app/helpers/
ð± helpersãã£ã¬ã¯ããªã«ã¯devise_helper.rb
ããããããã«ã¯ãã¥ã¼ãã«ãã¼ãç½®ããã¦ããããdevise_error_messages!
ã¯ããªãã¼ã·ã§ã³ã¨ã©ã¼ã表示ãããã«ãã¼ãªã®ã ãã©ãç¾å¨ã¯ããªãã¼ã·ã§ã³ã¨ã©ã¼è¡¨ç¤ºã®ãã¼ã·ã£ã«ãç´æ¥ã¬ã³ããªã³ã°ããããã«å¤æ´ããã¦ãã¦ãå¾æ¹äºææ§ãç¶æããããã«æ®ããã¦ãããã
# app/helpers/devise_helper.rb module DeviseHelper # Retain this method for backwards compatibility, deprecated in favor of modifying the # devise/shared/error_messages partial. def devise_error_messages! ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc [Devise] `DeviseHelper#devise_error_messages!` is deprecated and will be removed in the next major version. Devise now uses a partial under "devise/shared/error_messages" to display error messages by default, and make them easier to customize. Update your views changing calls from: <%= devise_error_messages! %> to: <%= render "devise/shared/error_messages", resource: resource %> To start customizing how errors are displayed, you can copy the partial from devise to your `app/views` folder. Alternatively, you can run `rails g devise:views` which will copy all of them again to your app. DEPRECATION return "" if resource.errors.empty? render "devise/shared/error_messages", resource: resource end end
ð± appãã£ã¬ã¯ããªã¯ãããªæãã ãã
lib/
ð± libé ä¸ã¯ã¨ã¦ã大ããã¦å ¨é¨ã¯èª¬æã§ããªãã®ã§ãç¥ã£ã¦ããã¨å½¹ã«ç«ã¡ãããªç®æãããã¯ã¢ãããã¦ãããã
lib/devise/
ð± åºæ¬çã«ã³ã¢ã¨ãªãã³ã¼ãã¯lib/devise/
é
ä¸ã«ç½®ããã¦ãããã
lib/devise/controllers/
ð± ã³ã³ããã¼ã©ã¼ã§å©ç¨ãããã«ãã¼ãå®ç¾©ããã¦ãããã
rememberable.rb scoped_views.rb sign_in_out.rb store_location.rb url_helpers.rb helpers.rb
ð± ä¾ã¨ãã¦sign_in_out.rb
ãè¦ã¦ã¿ãããsign_in
ãsign_out
ãªã©ã®ããã°ã¤ã³/ãã°ã¢ã¦ãã«é¢ããã³ã³ããã¼ã©ã¼ãã«ãã¼ãå®ç¾©ããã¦ãããã
# lib/devise/controllers/sign_in_out.rb # frozen_string_literal: true module Devise module Controllers # Provide sign in and sign out functionality. # Included by default in all controllers. module SignInOut # Return true if the given scope is signed in session. If no scope given, return # true if any scope is signed in. This will run authentication hooks, which may # cause exceptions to be thrown from this method; if you simply want to check # if a scope has already previously been authenticated without running # authentication hooks, you can directly call `warden.authenticated?(scope: scope)` def signed_in?(scope = nil) [scope || Devise.mappings.keys].flatten.any? do |_scope| warden.authenticate?(scope: _scope) end end # Sign in a user that already was authenticated. This helper is useful for logging # users in after sign up. All options given to sign_in is passed forward # to the set_user method in warden. # If you are using a custom warden strategy and the timeoutable module, you have to # set `env["devise.skip_timeout"] = true` in the request to use this method, like we do # in the sessions controller: https://github.com/heartcombo/devise/blob/master/app/controllers/devise/sessions_controller.rb#L7 # # Examples: # # sign_in :user, @user # sign_in(scope, resource) # sign_in @user # sign_in(resource) # sign_in @user, event: :authentication # sign_in(resource, options) # sign_in @user, store: false # sign_in(resource, options) # def sign_in(resource_or_scope, *args) options = args.extract_options! scope = Devise::Mapping.find_scope!(resource_or_scope) resource = args.last || resource_or_scope expire_data_after_sign_in! if options[:bypass] ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller) [Devise] bypass option is deprecated and it will be removed in future version of Devise. Please use bypass_sign_in method instead. Example: bypass_sign_in(user) DEPRECATION warden.session_serializer.store(resource, scope) elsif warden.user(scope) == resource && !options.delete(:force) # Do nothing. User already signed in and we are not forcing it. true else warden.set_user(resource, options.merge!(scope: scope)) end end # Sign in a user bypassing the warden callbacks and stores the user straight in session. This option is useful in cases the user is already signed in, but we want to refresh the credentials in session. # # Examples: # # bypass_sign_in @user, scope: :user # bypass_sign_in @user def bypass_sign_in(resource, scope: nil) scope ||= Devise::Mapping.find_scope!(resource) expire_data_after_sign_in! warden.session_serializer.store(resource, scope) end # Sign out a given user or scope. This helper is useful for signing out a user # after deleting accounts. Returns true if there was a logout and false if there # is no user logged in on the referred scope # # Examples: # # sign_out :user # sign_out(scope) # sign_out @user # sign_out(resource) # def sign_out(resource_or_scope = nil) return sign_out_all_scopes unless resource_or_scope scope = Devise::Mapping.find_scope!(resource_or_scope) user = warden.user(scope: scope, run_callbacks: false) # If there is no user warden.logout(scope) warden.clear_strategies_cache!(scope: scope) instance_variable_set(:"@current_#{scope}", nil) !!user end # Sign out all active users or scopes. This helper is useful for signing out all roles # in one click. This signs out ALL scopes in warden. Returns true if there was at least one logout # and false if there was no user logged in on all scopes. def sign_out_all_scopes(lock = true) users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) } warden.logout expire_data_after_sign_out! warden.clear_strategies_cache! warden.lock! if lock users.any? end private def expire_data_after_sign_in! # session.keys will return an empty array if the session is not yet loaded. # This is a bug in both Rack and Rails. # A call to #empty? forces the session to be loaded. session.empty? session.keys.grep(/^devise\./).each { |k| session.delete(k) } end alias :expire_data_after_sign_out! :expire_data_after_sign_in! end end end
lib/devise/models/
ð± Userã¢ãã«ã«è¿½å ãããã¡ã½ãããã¢ã¸ã¥ã¼ã«æ¯ã«å®ç¾©ããã¦ãããã
confirmable.rb database_authenticatable.rb lockable.rb omniauthable.rb recoverable.rb registerable.rb rememberable.rb timeoutable.rb trackable.rb validatable.rb authenticatable.rb
ð± ä¾ã¨ãã¦trackable.rb
ãè¦ã¦ã¿ãããIPã¢ãã¬ã¹ã»ãã°ã¤ã³æå»ã»ãã°ã¤ã³åæ°ãæ´æ°ããã¡ã½ãããå®ç¾©ããã¦ããããããã§å®ç¾©ããã¦ããã¡ã½ããã¯user.update_tracked_fields!(request)
ã®ããã«ãã¦å©ç¨ã§ãããã
# lib/devise/models/trackable.rb # frozen_string_literal: true require 'devise/hooks/trackable' module Devise module Models # Track information about your user sign in. It tracks the following columns: # # * sign_in_count - Increased every time a sign in is made (by form, openid, oauth) # * current_sign_in_at - A timestamp updated when the user signs in # * last_sign_in_at - Holds the timestamp of the previous sign in # * current_sign_in_ip - The remote ip updated when the user sign in # * last_sign_in_ip - Holds the remote ip of the previous sign in # module Trackable def self.required_fields(klass) [:current_sign_in_at, :current_sign_in_ip, :last_sign_in_at, :last_sign_in_ip, :sign_in_count] end def update_tracked_fields(request) old_current, new_current = self.current_sign_in_at, Time.now.utc self.last_sign_in_at = old_current || new_current self.current_sign_in_at = new_current old_current, new_current = self.current_sign_in_ip, extract_ip_from(request) self.last_sign_in_ip = old_current || new_current self.current_sign_in_ip = new_current self.sign_in_count ||= 0 self.sign_in_count += 1 end def update_tracked_fields!(request) # We have to check if the user is already persisted before running # `save` here because invalid users can be saved if we don't. # See https://github.com/heartcombo/devise/issues/4673 for more details. return if new_record? update_tracked_fields(request) save(validate: false) end protected def extract_ip_from(request) request.remote_ip end end end end
lib/devise/strategies/
ð± Wardenã®Strategyãå©ç¨ããèªè¨¼ãå®ç¾©ããã¦ãããã
authenticatable.rb base.rb database_authenticatable.rb rememberable.rb
ð± ä¾ã¨ãã¦database_authenticatable.rb
ãè¦ã¦ã¿ãããããã§ã¯Database Authenticatableã¢ã¸ã¥ã¼ã«ç¨ã®Strategyãå®ç¾©ããã¦ããããauthenticate!
ã¡ã½ãããè¦ãã¨ãemailã¨passwordãå©ç¨ãã¦èªè¨¼ãã¦ãããã¨ãããããã
# lib/devise/strategies/database_authenticatable.rb # frozen_string_literal: true require 'devise/strategies/authenticatable' module Devise module Strategies # Default strategy for signing in a user, based on their email and password in the database. class DatabaseAuthenticatable < Authenticatable def authenticate! resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash) hashed = false if validate(resource){ hashed = true; resource.valid_password?(password) } remember_me(resource) resource.after_database_authentication success!(resource) end # In paranoid mode, hash the password even when a resource doesn't exist for the given authentication key. # This is necessary to prevent enumeration attacks - e.g. the request is faster when a resource doesn't # exist in the database if the password hashing algorithm is not called. mapping.to.new.password = password if !hashed && Devise.paranoid unless resource Devise.paranoid ? fail(:invalid) : fail(:not_found_in_database) end end end end end Warden::Strategies.add(:database_authenticatable, Devise::Strategies::DatabaseAuthenticatable)
lib/devise/hooks/
ð± Wardenã®Callbackæ©è½ãå©ç¨ããhookå¦çãå®ç¾©ããã¦ããããWardenã®Callbackæ©è½ã«ã¤ãã¦ã¯ Callbacks · wardencommunity/warden Wiki · GitHub ãåç §ãã¦ãã
csrf_cleaner.rb forgetable.rb lockable.rb proxy.rb rememberable.rb timeoutable.rb trackable.rb activatable.rb
ð± ä¾ã¨ãã¦trackable.rb
ãè¦ã¦ã¿ãããTrackableã¢ã¸ã¥ã¼ã«ãæå¹ãªå ´åããã°ã¤ã³æï¼after_set_useræï¼ã«IPã¢ãã¬ã¹ã»ãã°ã¤ã³æå»ã»ãã°ã¤ã³åæ°ãæ´æ°ãã¦ãããã¨ãããããã
# lib/devise/hooks/trackable.rb # frozen_string_literal: true # After each sign in, update sign in time, sign in count and sign in IP. # This is only triggered when the user is explicitly set (with set_user) # and on authentication. Retrieving the user from session (:fetch) does # not trigger it. Warden::Manager.after_set_user except: :fetch do |record, warden, options| if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope]) && !warden.request.env['devise.skip_trackable'] record.update_tracked_fields!(warden.request) end end
lib/devise/test/
ð± ãã¹ãã§å©ç¨ãããã«ãã¼ãå®ç¾©ããã¦ãããã
controller_helpers.rb integration_helpers.rb
ð± ä¾ã¨ãã¦integration_helpers.rb
ãè¦ã¦ã¿ãããããã«ã¯Integrationãã¹ãã«å¯¾ãã¦ãã«ãã¼ãæä¾ããDevise::Test::IntegrationHelpers
ã¢ã¸ã¥ã¼ã«ãå®ç¾©ããã¦ãããããã®ã¢ã¸ã¥ã¼ã«ãincludeãããã¨ã§ãã¹ãã§sign_in
ã¨sign_out
ãå©ç¨ã§ããããã«ãªããã
# lib/devise/test/integration_helpers.rb # frozen_string_literal: true module Devise # Devise::Test::IntegrationHelpers is a helper module for facilitating # authentication on Rails integration tests to bypass the required steps for # signin in or signin out a record. # # Examples # # class PostsTest < ActionDispatch::IntegrationTest # include Devise::Test::IntegrationHelpers # # test 'authenticated users can see posts' do # sign_in users(:bob) # # get '/posts' # assert_response :success # end # end module Test module IntegrationHelpers def self.included(base) base.class_eval do include Warden::Test::Helpers setup :setup_integration_for_devise teardown :teardown_integration_for_devise end end # Signs in a specific resource, mimicking a successful sign in # operation through +Devise::SessionsController#create+. # # * +resource+ - The resource that should be authenticated # * +scope+ - An optional +Symbol+ with the scope where the resource # should be signed in with. def sign_in(resource, scope: nil) scope ||= Devise::Mapping.find_scope!(resource) login_as(resource, scope: scope) end # Signs out a specific scope from the session. # # * +resource_or_scope+ - The resource or scope that should be signed out. def sign_out(resource_or_scope) scope = Devise::Mapping.find_scope!(resource_or_scope) logout scope end protected def setup_integration_for_devise Warden.test_mode! end def teardown_integration_for_devise Warden.test_reset! end end end end
lib/devise/rails.rb
ð± Deviseã®Rails Engineãå®ç¾©ããã¦ãããã
# lib/devise/rails.rb # frozen_string_literal: true require 'devise/rails/routes' require 'devise/rails/warden_compat' module Devise class Engine < ::Rails::Engine config.devise = Devise # Initialize Warden and copy its configurations. config.app_middleware.use Warden::Manager do |config| Devise.warden_config = config end # Force routes to be loaded if we are doing any eager load. config.before_eager_load do |app| app.reload_routes! if Devise.reload_routes end initializer "devise.url_helpers" do Devise.include_helpers(Devise::Controllers) end initializer "devise.omniauth", after: :load_config_initializers, before: :build_middleware_stack do |app| Devise.omniauth_configs.each do |provider, config| app.middleware.use config.strategy_class, *config.args do |strategy| config.strategy = strategy end end if Devise.omniauth_configs.any? Devise.include_helpers(Devise::OmniAuth) end end initializer "devise.secret_key" do |app| Devise.secret_key ||= Devise::SecretKeyFinder.new(app).find Devise.token_generator ||= if secret_key = Devise.secret_key Devise::TokenGenerator.new( ActiveSupport::CachingKeyGenerator.new(ActiveSupport::KeyGenerator.new(secret_key)) ) end end end end
lib/devise/rails/routes.rb
ð± devise_for
ãdevise_scope
ãªã©ã®ã«ã¼ãã£ã³ã°ã§å©ç¨ããã¡ã½ãããå®ç¾©ããã¦ãããã
# lib/devise/rails/routes.rb # ...çç¥... def devise_for(*resources) @devise_finalized = false raise_no_secret_key unless Devise.secret_key options = resources.extract_options! options[:as] ||= @scope[:as] if @scope[:as].present? options[:module] ||= @scope[:module] if @scope[:module].present? options[:path_prefix] ||= @scope[:path] if @scope[:path].present? options[:path_names] = (@scope[:path_names] || {}).merge(options[:path_names] || {}) options[:constraints] = (@scope[:constraints] || {}).merge(options[:constraints] || {}) options[:defaults] = (@scope[:defaults] || {}).merge(options[:defaults] || {}) options[:options] = @scope[:options] || {} options[:options][:format] = false if options[:format] == false resources.map!(&:to_sym) resources.each do |resource| mapping = Devise.add_mapping(resource, options) begin raise_no_devise_method_error!(mapping.class_name) unless mapping.to.respond_to?(:devise) rescue NameError => e raise unless mapping.class_name == resource.to_s.classify warn "[WARNING] You provided devise_for #{resource.inspect} but there is " \ "no model #{mapping.class_name} defined in your application" next rescue NoMethodError => e raise unless e.message.include?("undefined method `devise'") raise_no_devise_method_error!(mapping.class_name) end if options[:controllers] && options[:controllers][:omniauth_callbacks] unless mapping.omniauthable? raise ArgumentError, "Mapping omniauth_callbacks on a resource that is not omniauthable\n" \ "Please add `devise :omniauthable` to the `#{mapping.class_name}` model" end end routes = mapping.used_routes devise_scope mapping.name do with_devise_exclusive_scope mapping.fullpath, mapping.name, options do routes.each { |mod| send("devise_#{mod}", mapping, mapping.controllers) } end end end end # Allow you to add authentication request from the router. # Takes an optional scope and block to provide constraints # on the model instance itself. # # authenticate do # resources :post # end # # authenticate(:admin) do # resources :users # end # # authenticate :user, lambda {|u| u.role == "admin"} do # root to: "admin/dashboard#show", as: :user_root # end # def authenticate(scope = nil, block = nil) constraints_for(:authenticate!, scope, block) do yield end end # Allow you to route based on whether a scope is authenticated. You # can optionally specify which scope and a block. The block accepts # a model and allows extra constraints to be done on the instance. # # authenticated :admin do # root to: 'admin/dashboard#show', as: :admin_root # end # # authenticated do # root to: 'dashboard#show', as: :authenticated_root # end # # authenticated :user, lambda {|u| u.role == "admin"} do # root to: "admin/dashboard#show", as: :user_root # end # # root to: 'landing#show' # def authenticated(scope = nil, block = nil) constraints_for(:authenticate?, scope, block) do yield end end # Allow you to route based on whether a scope is *not* authenticated. # You can optionally specify which scope. # # unauthenticated do # as :user do # root to: 'devise/registrations#new' # end # end # # root to: 'dashboard#show' # def unauthenticated(scope = nil) constraint = lambda do |request| not request.env["warden"].authenticate? scope: scope end constraints(constraint) do yield end end # Sets the devise scope to be used in the controller. If you have custom routes, # you are required to call this method (also aliased as :as) in order to specify # to which controller it is targeted. # # as :user do # get "sign_in", to: "devise/sessions#new" # end # # Notice you cannot have two scopes mapping to the same URL. And remember, if # you try to access a devise controller without specifying a scope, it will # raise ActionNotFound error. # # Also be aware of that 'devise_scope' and 'as' use the singular form of the # noun where other devise route commands expect the plural form. This would be a # good and working example. # # devise_scope :user do # get "/some/route" => "some_devise_controller" # end # devise_for :users # # Notice and be aware of the differences above between :user and :users def devise_scope(scope) constraint = lambda do |request| request.env["devise.mapping"] = Devise.mappings[scope] true end constraints(constraint) do yield end end # ...çç¥...
lib/generators/
ð± ã³ã³ããã¼ã©ã¼ããã¥ã¼ãªã©ãä½æããããã®ã¸ã§ãã¬ã¼ã¿ã¼ãç½®ããã¦ãããã
lib/devies.rb
ð± Devise
ã¢ã¸ã¥ã¼ã«ãå®ç¾©ããã¦ãã¦ãã¢ã¸ã¥ã¼ã«ã®autoloadãè¡ã£ã¦ãããã
# lib/devies.rb # frozen_string_literal: true require 'rails' require 'active_support/core_ext/numeric/time' require 'active_support/dependencies' require 'orm_adapter' require 'set' require 'securerandom' require 'responders' module Devise autoload :Delegator, 'devise/delegator' autoload :Encryptor, 'devise/encryptor' autoload :FailureApp, 'devise/failure_app' autoload :OmniAuth, 'devise/omniauth' autoload :ParameterFilter, 'devise/parameter_filter' autoload :ParameterSanitizer, 'devise/parameter_sanitizer' autoload :TestHelpers, 'devise/test_helpers' autoload :TimeInflector, 'devise/time_inflector' autoload :TokenGenerator, 'devise/token_generator' autoload :SecretKeyFinder, 'devise/secret_key_finder' module Controllers autoload :Helpers, 'devise/controllers/helpers' autoload :Rememberable, 'devise/controllers/rememberable' autoload :ScopedViews, 'devise/controllers/scoped_views' autoload :SignInOut, 'devise/controllers/sign_in_out' autoload :StoreLocation, 'devise/controllers/store_location' autoload :UrlHelpers, 'devise/controllers/url_helpers' end module Hooks autoload :Proxy, 'devise/hooks/proxy' end module Mailers autoload :Helpers, 'devise/mailers/helpers' end module Strategies autoload :Base, 'devise/strategies/base' autoload :Authenticatable, 'devise/strategies/authenticatable' end module Test autoload :ControllerHelpers, 'devise/test/controller_helpers' autoload :IntegrationHelpers, 'devise/test/integration_helpers' end # ...çç¥... end
ð± ãã¨åè¨å®ã®ããã©ã«ãå¤ãããã§ã»ããããã¦ãããã
# lib/devies.rb # ...çç¥... # Secret key used by the key generator mattr_accessor :secret_key @@secret_key = nil # Custom domain or key for cookies. Not set by default mattr_accessor :rememberable_options @@rememberable_options = {} # The number of times to hash the password. mattr_accessor :stretches @@stretches = 12 # The default key used when authenticating over http auth. mattr_accessor :http_authentication_key @@http_authentication_key = nil # Keys used when authenticating a user. mattr_accessor :authentication_keys @@authentication_keys = [:email] # Request keys used when authenticating a user. mattr_accessor :request_keys @@request_keys = [] # Keys that should be case-insensitive. mattr_accessor :case_insensitive_keys @@case_insensitive_keys = [:email] # Keys that should have whitespace stripped. mattr_accessor :strip_whitespace_keys @@strip_whitespace_keys = [:email] # If http authentication is enabled by default. mattr_accessor :http_authenticatable @@http_authenticatable = false # If http headers should be returned for ajax requests. True by default. mattr_accessor :http_authenticatable_on_xhr @@http_authenticatable_on_xhr = true # If params authenticatable is enabled by default. mattr_accessor :params_authenticatable @@params_authenticatable = true # The realm used in Http Basic Authentication. mattr_accessor :http_authentication_realm @@http_authentication_realm = "Application" # Email regex used to validate email formats. It asserts that there are no # @ symbols or whitespaces in either the localpart or the domain, and that # there is a single @ symbol separating the localpart and the domain. mattr_accessor :email_regexp @@email_regexp = /\A[^@\s]+@[^@\s]+\z/ # Range validation for password length mattr_accessor :password_length @@password_length = 6..128 # The time the user will be remembered without asking for credentials again. mattr_accessor :remember_for @@remember_for = 2.weeks # If true, extends the user's remember period when remembered via cookie. mattr_accessor :extend_remember_period @@extend_remember_period = false # If true, all the remember me tokens are going to be invalidated when the user signs out. mattr_accessor :expire_all_remember_me_on_sign_out @@expire_all_remember_me_on_sign_out = true # Time interval you can access your account before confirming your account. # nil - allows unconfirmed access for unlimited time mattr_accessor :allow_unconfirmed_access_for @@allow_unconfirmed_access_for = 0.days # Time interval the confirmation token is valid. nil = unlimited mattr_accessor :confirm_within @@confirm_within = nil # Defines which key will be used when confirming an account. mattr_accessor :confirmation_keys @@confirmation_keys = [:email] # Defines if email should be reconfirmable. mattr_accessor :reconfirmable @@reconfirmable = true # Time interval to timeout the user session without activity. mattr_accessor :timeout_in @@timeout_in = 30.minutes # Used to hash the password. Please generate one with rails secret. mattr_accessor :pepper @@pepper = nil # Used to send notification to the original user email when their email is changed. mattr_accessor :send_email_changed_notification @@send_email_changed_notification = false # Used to enable sending notification to user when their password is changed. mattr_accessor :send_password_change_notification @@send_password_change_notification = false # Scoped views. Since it relies on fallbacks to render default views, it's # turned off by default. mattr_accessor :scoped_views @@scoped_views = false # Defines which strategy can be used to lock an account. # Values: :failed_attempts, :none mattr_accessor :lock_strategy @@lock_strategy = :failed_attempts # Defines which key will be used when locking and unlocking an account mattr_accessor :unlock_keys @@unlock_keys = [:email] # Defines which strategy can be used to unlock an account. # Values: :email, :time, :both mattr_accessor :unlock_strategy @@unlock_strategy = :both # Number of authentication tries before locking an account mattr_accessor :maximum_attempts @@maximum_attempts = 20 # Time interval to unlock the account if :time is defined as unlock_strategy. mattr_accessor :unlock_in @@unlock_in = 1.hour # Defines which key will be used when recovering the password for an account mattr_accessor :reset_password_keys @@reset_password_keys = [:email] # Time interval you can reset your password with a reset password key mattr_accessor :reset_password_within @@reset_password_within = 6.hours # When set to false, resetting a password does not automatically sign in a user mattr_accessor :sign_in_after_reset_password @@sign_in_after_reset_password = true # The default scope which is used by warden. mattr_accessor :default_scope @@default_scope = nil # Address which sends Devise e-mails. mattr_accessor :mailer_sender @@mailer_sender = nil # Skip session storage for the following strategies mattr_accessor :skip_session_storage @@skip_session_storage = [:http_auth] # Which formats should be treated as navigational. mattr_accessor :navigational_formats @@navigational_formats = ["*/*", :html] # When set to true, signing out a user signs out all other scopes. mattr_accessor :sign_out_all_scopes @@sign_out_all_scopes = true # The default method used while signing out mattr_accessor :sign_out_via @@sign_out_via = :delete # The parent controller all Devise controllers inherits from. # Defaults to ApplicationController. This should be set early # in the initialization process and should be set to a string. mattr_accessor :parent_controller @@parent_controller = "ApplicationController" # The parent mailer all Devise mailers inherit from. # Defaults to ActionMailer::Base. This should be set early # in the initialization process and should be set to a string. mattr_accessor :parent_mailer @@parent_mailer = "ActionMailer::Base" # The router Devise should use to generate routes. Defaults # to :main_app. Should be overridden by engines in order # to provide custom routes. mattr_accessor :router_name @@router_name = nil # Set the OmniAuth path prefix so it can be overridden when # Devise is used in a mountable engine mattr_accessor :omniauth_path_prefix @@omniauth_path_prefix = nil # Set if we should clean up the CSRF Token on authentication mattr_accessor :clean_up_csrf_token_on_authentication @@clean_up_csrf_token_on_authentication = true # When false, Devise will not attempt to reload routes on eager load. # This can reduce the time taken to boot the app but if your application # requires the Devise mappings to be loaded during boot time the application # won't boot properly. mattr_accessor :reload_routes @@reload_routes = true # PRIVATE CONFIGURATION # Store scopes mappings. mattr_reader :mappings @@mappings = {} # OmniAuth configurations. mattr_reader :omniauth_configs @@omniauth_configs = {} # Define a set of modules that are called when a mapping is added. mattr_reader :helpers @@helpers = Set.new @@helpers << Devise::Controllers::Helpers # Private methods to interface with Warden. mattr_accessor :warden_config @@warden_config = nil @@warden_config_blocks = [] # When true, enter in paranoid mode to avoid user enumeration. mattr_accessor :paranoid @@paranoid = false # When true, warn user if they just used next-to-last attempt of authentication mattr_accessor :last_attempt_warning @@last_attempt_warning = true # Stores the token generator mattr_accessor :token_generator @@token_generator = nil # When set to false, changing a password does not automatically sign in a user mattr_accessor :sign_in_after_change_password @@sign_in_after_change_password = true # ...çç¥...
第14ç« èªè¨¼gemã®æ¯è¼
æéåãã§ãããæ°ãåãããæ¸ãã¾ãðââï¸
ï¼ä»¥ä¸è¿½è¨
ã¡ãã£ã¨æ°ãåããªãããªã®ã§ãç°¡åã«ã§ããDeviseã«å¯¾ããææ³ã¾ã¨ãã¦ããã¾ãðââï¸
Deviseã®è¯ãã¨ãã
- ã¢ã¸ã¥ã¼ã«ã追å ããã ãã§ä¸éãã®èªè¨¼æ©è½ã使ããã®ã§ãã³ã¼ããæ¸ãéãæãããã
- ã ãããç使ã£ããã¨ãããã®ã§ãæ°è¦ã®å¦ç¿ã³ã¹ããæãããã
- ã¨ã³ã·ã¹ãã ãçºéãã¦ããã®ã§ãã¢ã¸ã¥ã¼ã«ã追å ããã ãã§ã³ã¼ããæ¸ããã«ä¾¿å©æ©è½ã追å ã§ããï¼Devise Securityã使ã£ã¦ã¨ã³ã¿ã¼ãã©ã¤ãºãªã»ãã¥ãªãã£ã¼æ©è½ã追å ãããï¼
Deviseã®æªãã¨ãã
- ãã¼ãã«è¨è¨ãã¤ããï¼usersãã¼ãã«ã«å ¨ã¦ã®ã«ã©ã ãè©°ãè¾¼ãã§ããã®ã§Userãfatã«ãªãããã and nullableãªã«ã©ã ãããããã§ãã¦ãã¾ãï¼
- ã«ã¹ã¿ãã¤ãºãã¤ããï¼ã¬ã¼ã«ããå¤ããã«ã¹ã¿ãã¤ãºãããéã«Devise gemã®ã³ã¼ããèªãå¿ è¦ããã and ã³ã¼ããã¼ã¹ã大ããä¸ã«Wardenã§æ½è±¡åããã¦ãã¦ã³ã¼ãèªãã®ãã¤ããï¼
Deviseã¯çµæ§ãªã¤ãã¿ãããã¾ããéçºã®æåã®é ã¯ã¢ã¸ã¥ã¼ã«ã追å ããã ãã§ããããªæ©è½ã使ãã¦ã»ãã»ããªã®ã§ãããéçºãé²ã¿ãµã¼ãã¹ã大ãããªãã«ã¤ãã¦ã©ãã©ãã¤ãã¿ãå¢ãã¦ãã¾ããè¯ãã¨ãããããããããã®ã§ãããã»ã¨ãã©ã®å ´åã«ããã¦ã¤ãã¿ãåãããããªãããªã¨æã£ã¦ã¾ãããªã®ã§å人çã«ã¯Deviseã¯ä½¿ããã«Sorceryã¨ãã使ããã¨ããããããã¾ãã
Deviseãåãã¦ãããµã¼ãã¹ã¯ãã«ã¹ã¿ãã¤ãºã¯ãã¥ã¼ã ãã§ãã¨ã¯å ¨é¨Deviseã®æ©è½ã§ã¾ããªãããããªå°è¦æ¨¡ãªãµã¼ãã¹ã§ããå人éçºã¨ãããã ããã®å ´åã§ãããã¦Deviseã使ãå¿ è¦ããããã¨è¨ãããã¨......ãã¼ãã
ã¨ãããã¨ã§Deviseã®è¨äºãæ¸ãã¦ããã¦Deviseã¯ã§ããã°ä½¿ããªãã»ããããã¨ããæ²ããçµè«ã«ãªã£ã¦ãã¾ãã¾ããã
ãããã¨noteã®ä»¶ã§ã»ãã¥ãªãã£çã«å±éºãªããããªããã¨ãã話ãåºãããã¾ããããããã©ã«ãã§ã¯IPã¢ãã¬ã¹çã®ã«ã©ã ã¯ã·ãªã¢ã©ã¤ãºããªãããã«å¯¾çããã¦ããã®ã§ãããã¯ã¡ãã£ã¨å¥ã®è©±ããªã¨æã£ãããã¾ããDeviseã¯å±éºãªã®ã§èªè¨¼ãèªä½ãããã¿ãããªè©±ããããã§è¦ã¾ããããèªä½ã®èªè¨¼ããDeviseã®ããã£ã½ã©å®å ¨ãªã®ã§èªä½ããããããªãDeviseããããããã¾ãã
060 Devise
061 Sorcery
062 Clearance
063 Authlogic
064 èªè¨¼gemã®æ¯è¼ã¾ã¨ã
Deviseã®æ å ±æº
æ¥æ¬èªã®æ å ±æº
ð± Deviseã®ReadMeã®ç¿»è¨³ã ãã
Deviseã®READMEã翻訳ãã¦ã¿ã - Qiita
Railsã®ç¬¬4ä¸ä»£èªè¨¼ã¨ã³ã¸ã³Deviseã®READMEã翻訳ãã¦ã¿ã - babie, you're my home
ð± Deviseã®åºæ¬çãªä½¿ãæ¹ã詳ããæ¸ããã¦ãããã
[Rails] deviseã®ä½¿ãæ¹ï¼rails6çï¼ - Qiita
#209 Introducing Devise - RailsCasts
#210 Customizing Devise - RailsCasts
ð± TechRachoããã®Deviseã®Wikiã®ã¾ã¨ãã ããDeviseã®Wikiã¯ãã¼ã¸æ°ãå¤ãã®ã§ãç®å½ã¦ã®ãã¼ã¸ãæ¢ãéã«å½¹ç«ã¤ãã
[Rails] Devise Wikiæ¥æ¬èªããã1ãã¯ã¼ã¯ããã¼ã®ã«ã¹ã¿ãã¤ãºãï¼æ¦è¦ã»ç¨éä»ãï¼ï½TechRachoï¼ããã¯ã©ããã§ï¼ãã¨ã³ã¸ãã¢ã®ãï¼ãããï¼ãã«ãï½BPSæ ªå¼ä¼ç¤¾
[Rails] Devise Wikiæ¥æ¬èªããã2ãèªè¨¼æ¹æ³ã®ã«ã¹ã¿ãã¤ãºããOmniAuthãï¼æ¦è¦ã»ç¨éä»ãï¼ï½TechRachoï¼ããã¯ã©ããã§ï¼ãã¨ã³ã¸ãã¢ã®ãï¼ãããï¼ãã«ãï½BPSæ ªå¼ä¼ç¤¾
[Rails] Devise Wikiæ¥æ¬èªããã3ããã¥ã¼/ã³ã³ãã³ãã®ã«ã¹ã¿ãã¤ãºããç¹æ¨©/èªè¨¼ãï½TechRachoï¼ããã¯ã©ããã§ï¼ãã¨ã³ã¸ãã¢ã®ãï¼ãããï¼ãã«ãï½BPSæ ªå¼ä¼ç¤¾
[Rails] Devise Wikiæ¥æ¬èªããã4ããã¹ãããç¹æ®ãªè¨å®ãï½TechRachoï¼ããã¯ã©ããã§ï¼ãã¨ã³ã¸ãã¢ã®ãï¼ãããï¼ãã«ãï½BPSæ ªå¼ä¼ç¤¾
[Rails] Devise Wikiæ¥æ¬èªããã5ãã¢ããªã§ã®ãã®ä»ã®è¨å®ããJavaScriptãï½TechRachoï¼ããã¯ã©ããã§ï¼ãã¨ã³ã¸ãã¢ã®ãï¼ãããï¼ãã«ãï½BPSæ ªå¼ä¼ç¤¾
[Rails] Devise Wikiæ¥æ¬èªããã6ãä»ã®èªè¨¼ãã©ã°ã¤ã³ããã®ç§»è¡ããã¢ããã°ã¬ã¼ããï½TechRachoï¼ããã¯ã©ããã§ï¼ãã¨ã³ã¸ãã¢ã®ãï¼ãããï¼ãã«ãï½BPSæ ªå¼ä¼ç¤¾
è±èªã®æ å ±æº
ð± æ¬å®¶ãªãã¸ããªã ãã
GitHub - heartcombo/devise: Flexible authentication solution for Rails with Warden.
ð± æ¬å®¶Wikiã ããã«ã¹ã¿ãã¤ãºæ¹æ³ãå å®ãã¦ããã©ããã¼ã¸æ°ãå¤ãã®ã§å ¨é¨èªãã®ã¯ãªããªã大å¤ã ããTechRachoããã®ã¾ã¨ããããç®å½ã¦ã®ãã¼ã¸ãæ¢ãã®ãããããã ãã
Home · heartcombo/devise Wiki · GitHub
ãã¼ãã·ã¼ã
å¾ããè¦è¿ãç¨ã®ã¾ã¨ã
ã³ã³ããã¼ã©ã¼ã»ãã¥ã¼ã®ã¡ã½ãã
# ãªã¯ã¨ã¹ããã¦ããã¦ã¼ã¶ã¼ãèªè¨¼ããã # ã¦ã¼ã¶ã¼ããã°ã¤ã³æ¸ã¿ã®å ´åã¯ã¢ã¯ã»ã¹ã許å¯ãã¦ãæªãã°ã¤ã³ã®å ´åã¯root_pathã«ãªãã¤ã¬ã¯ãããã # ã³ã³ããã¼ã©ã¼ã§`before_action :authenticate_user!`ã®å½¢ã§å©ç¨ããã authenticate_user! # ãã°ã¤ã³æ¸ã¿ã®å ´åã¯ãã°ã¤ã³ã¦ã¼ã¶ã¼ãè¿ãã current_user # ãã°ã¤ã³æ¸ã¿ã®å ´åã¯trueãè¿ãã user_signed_in? # ã¦ã¼ã¶ã¼ã«ç´ã¥ãsessionãè¿ãã user_session # Deviseã®ã³ã³ããã¼ã©ã¼ã ã£ããtrueãè¿ãã devise_controller? # ãã°ã¤ã³ãããã sign_in(user) # Wardenã®ã³ã¼ã«ããã¯ããã¤ãã¹ãã¦ãã°ã¤ã³ãããã # ã¦ã¼ã¶ã¼ãèªè¨¼æ å ±ãå¤æ´ããéã«ãã°ã¢ã¦ããã¦ãã¾ãã®ã§ããããé²ãããã«å©ç¨ããã bypass_sign_in(user) # ãã°ã¢ã¦ããããã sign_out(user)
ã«ã¼ãã£ã³ã°ã®ã¡ã½ãã
# æå¹ãªã¢ã¸ã¥ã¼ã«ã«å¯¾å¿ããã«ã¼ãã£ã³ã°ãå®ç¾©ããã devise_for :users # ç¬èªã®ã«ã¼ãã£ã³ã°ãå®ç¾©ããã devise_scope :user do get "sign_in", to: "devise/sessions#new" end # ãã°ã¤ã³å¾ã®ã«ã¼ãã£ã³ã°ãå®ç¾©ããã authenticated do root to: 'dashboard#show', as: :authenticated_root end # ãã°ã¤ã³åã®ã«ã¼ãã£ã³ã°ãå®ç¾©ããã unauthenticated do root to: 'dashboard2#show', as: :unauthenticated_root end # èªè¨¼ä»ãã«ã¼ãã£ã³ã°ãå®ç¾©ããã authenticate do resources :cats end
ã¢ãã«ã®ã¡ã½ãã
# ==> Database Authenticatableã¢ã¸ã¥ã¼ã« # passwordãã»ããããã # å é¨ã§æå·åãã¦`encrypted_password`ã«ã»ãããã¦ããããã user.password = "password" # ãã¹ã¯ã¼ããæ£ãããã°trueã # å¼æ°ã®ãã¹ã¯ã¼ããããã·ã¥åãã¦encrypted_passwordã®å¤ã¨æ¯è¼ãã¦ãããã user.valid_password?('password') #=> true # passwordã¨password_confirmationã«nilãã»ããã user.clean_up_passwords # ==> Rememberableã¢ã¸ã¥ã¼ã« # remember_tokenãä½æ user.remember_me! # remember_tokenãåé¤ user.forget_me! # useræ å ±ã使ã£ã¦cookieãä½æ User.serialize_into_cookie(user) # cookieæ å ±ã使ã£ã¦userãåå¾ User.serialize_from_cookie(cookie_string) # ==> Recoverableã¢ã¸ã¥ã¼ã« # ãã¹ã¯ã¼ããªã»ããã¡ã¼ã«éä¿¡ user.send_reset_password_instructions # ãã¹ã¯ã¼ããªã»ãã # user.reset_password(new_password, new_password_confirmation) user.reset_password('password123', 'password123') # reset_password_tokenãæå¹æéå ãã©ããããreset_password_sent_atã使ãå¤å® user.reset_password_period_valid? #=> true # tokenã使ã£ã¦userãåå¾ User.with_reset_password_token(token) #=> user # ==> Timeoutableã¢ã¸ã¥ã¼ã« # ã¿ã¤ã ã¢ã¦ããªãtrue user.timedout?(Time.current) # ==> Lockableã¢ã¸ã¥ã¼ã« # ããã¯(ã¡ã¼ã«éä¿¡ããã) user.lock_access! # ããã¯(ã¡ã¼ã«éä¿¡ããªã) user.lock_access!(send_instructions: false) # ã¢ã³ãã㯠user.unlock_access! # ã¢ã³ããã¯ã®ã¡ã¼ã«éä¿¡ user.resend_unlock_instructions # ==> Confirmableã¢ã¸ã¥ã¼ã« # confirmãã # å ·ä½çã«ã¯confirmed_atã«ç¾å¨æå»ãè¨å®ãã user.confirm # confirmæ¸ã¿ãªããtrue user.confirmed? # æåã§Confirmã¡ã¼ã«ãéä¿¡ user.send_confirmation_instructions
ãªã³ã¯ï¼pathï¼
<!-- ãã°ã¤ã³å --> <%= link_to("ãµã¤ã³ã¢ãã", new_user_registration_path) %> <%= link_to("ãã°ã¤ã³", new_user_session_path) %> <%= link_to("ãã¹ã¯ã¼ãããå¿ãã§ããï¼", new_user_password_path) %> <%= link_to("ã¢ã«ã¦ã³ã確èªã®ã¡ã¼ã«ãåãåã£ã¦ãã¾ãããï¼", new_user_confirmation_path) %> <%= link_to("ã¢ã³ããã¯æ示ã®ã¡ã¼ã«ãåãåã£ã¦ãã¾ãããï¼", new_user_unlock_path) %> <!-- ãã°ã¤ã³å¾ --> <%= link_to("ãã°ã¢ã¦ã", destroy_user_session_path, method: :delete) %> <%= link_to("ã¢ã«ã¦ã³ãç·¨é", edit_user_registration_path) %> <%= link_to("ã¢ã«ã¦ã³ãåé¤", user_registration_path, method: :delete) %>
ã¢ã¸ã¥ã¼ã«
ã¢ã¸ã¥ã¼ã«å | æ©è½ | ããã©ã«ã |
---|---|---|
Registerable | ãµã¤ã³ã¢ããæ©è½ | æå¹ |
Database Authenticatable | Email/Passwordå ¥åã«ãããã°ã¤ã³æ©è½ | æå¹ |
Rememberable | Remember Meæ©è½ï¼ãã©ã¦ã¶ãéãã¦ããã°ã¤ã³ãç¶ç¶ããæ©è½ï¼ | æå¹ |
Recoverable | ãã¹ã¯ã¼ããªã»ããæ©è½ | æå¹ |
Validatable | Email/Passwordã®ããªãã¼ã·ã§ã³æ©è½ | æå¹ |
Confirmable | ãµã¤ã³ã¢ããæã«æ¬ç»é²ç¨ã®ã¡ã¼ã«ãéä¿¡ãã¦ãã¡ã¼ã«ã¢ãã¬ã¹ã確èªããæ©è½ | ç¡å¹ |
Trackable | ãã°ã¤ã³æã®æ å ±ï¼IPã¢ãã¬ã¹ãªã©ï¼ãDBã«ä¿åããæ©è½ | ç¡å¹ |
Timeoutable | ä¸å®æéã¢ã¯ã»ã¹ããªãã¨å¼·å¶ãã°ã¢ã¦ããããæ©è½ | ç¡å¹ |
Lockable | æå®åæ°ãã°ã¤ã³å¤±æã§ã¢ã«ã¦ã³ããããã¯ããæ©è½ | ç¡å¹ |
Omniauthable | Omniauthã¨ã®é£æºæ©è½ï¼Twitterã»Googleã¢ã«ã¦ã³ããªã©ã§ãã°ã¤ã³ã§ããï¼ | ç¡å¹ |
ã³ã³ããã¼ã©ã¼ã¨ã«ã¼ãã£ã³ã°
Registerableã¢ã¸ã¥ã¼ã«
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/sign_up | devise/registrations#new | ãµã¤ã³ã¢ããç»é¢ |
GET | /users/edit | devise/registrations#edit | ã¢ã«ã¦ã³ãç·¨éç»é¢ãemailãpasswordãç·¨éã§ããã |
POST | /users | devise/registrations#create | ã¢ã«ã¦ã³ãç»é² |
PATCH/PUT | /users | devise/registrations#update | ã¢ã«ã¦ã³ãæ´æ° |
DELETE | /users | devise/registrations#destroy | ã¢ã«ã¦ã³ãåé¤ |
GET | /users/cancel | devise/registrations#cancel | sessionåé¤ãOAuthã®sessionãã¼ã¿ãåé¤ãããå ´åã«ä½¿ãã |
Database Authenticatableã¢ã¸ã¥ã¼ã«
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/sign_in | devise/sessions#new | ãã°ã¤ã³ç»é¢ |
POST | /users/sign_in | devise/sessions#create | ãã°ã¤ã³ |
DELETE | /users/sign_out | devise/sessions#destroy | ãã°ã¢ã¦ã |
Recoverableã¢ã¸ã¥ã¼ã«
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/password/new | devise/passwords#new | ãã¹ã¯ã¼ããªã»ããã®ã¡ã¼ã«éä¿¡ç»é¢ |
GET | /users/password/edit | devise/passwords#edit | ãã¹ã¯ã¼ãåè¨å®ç»é¢ |
POST | /users/password | devise/passwords#create | ãã¹ã¯ã¼ããªã»ããã®ã¡ã¼ã«éä¿¡ |
PATCH/PUT | /users/password | devise/passwords#update | ãã¹ã¯ã¼ãåè¨å® |
Confirmableã¢ã¸ã¥ã¼ã«
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/confirmation | devise/confirmations#show | confirmã ã¡ã¼ã«ã®ãªã³ã¯å ã¯ããã ã¯ã¨ãªãã©ã¡ã¼ã¿ã¼ã®confirmation_tokenãä¸è´ããªãã¨ã¢ã¯ã»ã¹ã§ããªãã |
GET | /users/confirmation/new | devise/confirmations#new | confirmæ示ã¡ã¼ã«åéä¿¡ç»é¢ã |
POST | /users/confirmation | devise/confirmations#create | confirmæ示ã¡ã¼ã«éä¿¡ã |
Lockableã¢ã¸ã¥ã¼ã«
HTTPã¡ã½ãã | path | ã³ã³ããã¼ã©ã¼#ã¢ã¯ã·ã§ã³ | ç®ç |
---|---|---|---|
GET | /users/unlock | devise/unlocks#show | ã¢ã³ããã¯ã ã¡ã¼ã«ã®ãªã³ã¯å ã¯ããã ã¯ã¨ãªãã©ã¡ã¼ã¿ã¼ã®unlock_tokenãä¸è´ããªãã¨ã¢ã¯ã»ã¹ã§ããªãã |
GET | /users/unlock/new | devise/unlocks#new | ã¢ã³ããã¯æ示ã¡ã¼ã«åéä¿¡ç»é¢ã |
POST | /users/unlock | devise/unlocks#create | ã¢ã³ããã¯æ示ã¡ã¼ã«éä¿¡ã |
ã«ã©ã
Database Authenticatableã¢ã¸ã¥ã¼ã«
ã«ã©ã | æ¦è¦ |
---|---|
ã¡ã¼ã«ã¢ãã¬ã¹ã èªè¨¼ã«å©ç¨ã DBçã«ã¯ã¦ãã¼ã¯ãã¼ã«ãªããã¦ã¼ã¶ã¼ã¯éè¤ããã¡ã¼ã«ã¢ãã¬ã¹ãç»é²ãããã¨ãã§ããªããã |
|
encrypted_password | ããã·ã¥åããããã¹ã¯ã¼ãã èªè¨¼ã«å©ç¨ã ãã¹ã¯ã¼ããç´æ¥DBã«ä¿åããã®ã¯ã»ãã¥ãªãã£ã¼çã«åé¡ãããã®ã§ãããã·ã¥åãããã¹ã¯ã¼ããDBã«ä¿åããããDeviseã§ã¯å é¨çã«bcryptã¨ããããã·ã¥åé¢æ°ã使ã£ã¦ãã¦ãDBä¿ååã«èªåçã«ããã·ã¥åãã¦ããããã |
Rememberableã¢ã¸ã¥ã¼ã«
ã«ã©ã | æ¦è¦ |
---|---|
remember_created_at | Remenber Meããæå» |
remember_token | remember_meç¨ã®token remember_tokenã«ã©ã ããªããã°ãencrypted_passwordã®å é 30æåã§ä»£ç¨ããã®ã§ãå¥ã«ãªãã¦ãOKã ãããã¤ã°ã¬ã¼ã·ã§ã³ãã¡ã¤ã«ã«ãè¨è¼ãããªããã |
Recoverableã¢ã¸ã¥ã¼ã«
ã«ã©ã | æ¦è¦ |
---|---|
reset_password_token | ãã¹ã¯ã¼ããªã»ããã§å©ç¨ãããã¼ã¯ã³ã ä¸æã®ã©ã³ãã ãªãã¼ã¯ã³ãçæãããã ãã¹ã¯ã¼ããªã»ããã¡ã¼ã«ãããã¹ã¯ã¼ãåè¨å®ç»é¢ï¼ /users/password/edit ï¼ã¸ã¢ã¯ã»ã¹ããéã«ãã¦ã¼ã¶ã¼ãå¤å®ããã®ã«å©ç¨ããã |
reset_password_sent_at | ãã¹ã¯ã¼ããªã»ããã¡ã¼ã«éä¿¡æå»ã ãã¹ã¯ã¼ããªã»ããã¡ã¼ã«ã®æå¹æéã®å¤å®ã«å©ç¨ããã |
Confirmableã¢ã¸ã¥ã¼ã«
ã«ã©ã | æ¦è¦ |
---|---|
confirmation_token | confirmããéã«å©ç¨ãããã¼ã¯ã³ã ä¸æã®ã©ã³ãã ãªãã¼ã¯ã³ãçæãããã confirmæ示ã¡ã¼ã«ããconfirmã¢ã¯ã·ã§ã³ï¼ /users/confirmattion ï¼ã¸ã¢ã¯ã»ã¹ããéã«ãã¦ã¼ã¶ã¼ãå¤å®ããã®ã«å©ç¨ããã |
confirmed_at | confirmãããæå»ã confirmæ¸ã¿ãã©ããã¯ãã®ã«ã©ã ãnilãã©ããã§å¤å®ããã |
confirmation_sent_at | confirmation_tokenä½ææå»ã |
unconfirmed_email | ã¾ã confirmããã¦ããªãã¡ã¼ã«ã¢ãã¬ã¹ã emailå¤æ´æã®confirmã§å©ç¨ããã config.unconfirmed_email = true ã®å ´åã ãå¿
è¦ãconfirmãããã¾ã§ã¯æ°ããã¯emailã¯ãã®ã«ã©ã ã«ä¿åãããconfirmæã«emailã®ã«ã©ã ã«ã³ãã¼ãããã |
Trackableã¢ã¸ã¥ã¼ã«
ã«ã©ã | æ¦è¦ |
---|---|
sign_in_count | ãã°ã¤ã³åæ° |
current_sign_in_at | ææ°ã®ãã°ã¤ã³æå» |
last_sign_in_at | 1ã¤åã®ãã°ã¤ã³æå» |
current_sign_in_ip | ææ°ã®ãã°ã¤ã³æIPã¢ãã¬ã¹ |
last_sign_in_ip | 1ã¤åã®ãã°ã¤ã³æIPã¢ãã¬ã¹ |
Lockableã¢ã¸ã¥ã¼ã«
ã«ã©ã | æ¦è¦ |
---|---|
failed_attempts | 失æåæ°ãconfig.lock_strategy = :failed_attempts ã®å ´åã«ã ãå¿
è¦ã |
unlock_token | ã¡ã¼ã«ããã¢ã³ããã¯ããéã«å©ç¨ããtokenã ä¸æã®ã©ã³ãã ãªãã¼ã¯ã³ãçæãããã ã¢ã³ããã¯æ示ã¡ã¼ã«ããã¢ã³ããã¯ã¢ã¯ã·ã§ã³ï¼ /users/unlock ï¼ã¸ã¢ã¯ã»ã¹ããéã«ãã¦ã¼ã¶ã¼ãå¤å®ããã®ã«å©ç¨ãããconfig.unlock_strategy ã:email ã:both ã®å ´åã«ã ãå¿
è¦ã |
locked_at | ããã¯æå»ã ãããnullã§ãªãå ´åã«ããã¯ç¶æ ã¨ã¿ãªãããã |
ã¡ã¼ã«
Database Authenticatable
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#email_changed | Eã¡ã¼ã«å¤æ´å®äºã¡ã¼ã«ãEã¡ã¼ã«å¤æ´æã«éä¿¡ããã |
Devise::Mailer#password_change | ãã¹ã¯ã¼ãå¤æ´å®äºã¡ã¼ã«ããã¹ã¯ã¼ãå¤æ´æã«éä¿¡ããã |
Recoverable
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#reset_password_instructions | ãã¹ã¯ã¼ããªã»ããã¡ã¼ã« |
Confirmable
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#confirmation_instructions | confirmæ示ã¡ã¼ã« |
Lockable
ã¡ã¼ã©ã¼#ã¡ã½ãã | æ¦è¦ |
---|---|
Devise::Mailer#unlock_instructions | ã¢ã«ã¦ã³ãã¢ã³ããã¯æ示ã¡ã¼ã« |
ã¸ã§ãã¬ã¼ã¿ã¼
# è¨å®ãã¡ã¤ã«ã¨ãã±ã¼ã«ãã¡ã¤ã«ãä½æããã $ rails g devise:install # ã¢ãã«ãä½æããã # User以å¤ãæå®å¯è½ã $ rails g devise User $ rails g devise Admin # ãã¥ã¼ãã³ãã¼ããã # Scopeãæå®å¯è½ãScopeãæå®ããªãå ´åã¯`devise`åå空éã®ãã¥ã¼ãä½æãããã # `-v`ãªãã·ã§ã³ã§æå®ãã¥ã¼ã ããã³ãã¼ã§ããã $ rails g devise:views $ rails g devise:views user $ rails g devise:views -v registrations confirmations # ã³ã³ããã¼ã©ã¼ãä½æããã # ãã¥ã¼ã¨éãScopeæå®ã¯å¿ é ã # `-c`ãªãã·ã§ã³ã§æå®ã³ã³ããã¼ã©ã¼ã ãä½æã $ rails g devise:controllers users $ rails g devise:controllers users -c=sessions
è¨å®
# config/initializers/devise.rb # frozen_string_literal: true Devise.setup do |config| # Deviseã使ç¨ããç§å¯éµã # Deviseã¯ãã®ãã¼ãå©ç¨ãã¦tokenãä½æããï¼confirmation_tokenãreset_password_tokenãunlock_tokenï¼ã # ãã®ãã¼ãå¤æ´ããã¨å ¨ã¦ã®tokenãç¡å¹ã«ãªãã # ããã©ã«ãã§ã¯secret_key_baseãsecret_keyã¨ãã¦å©ç¨ããã # config.secret_key = '48bf747d05636bd17b63751533ac6879106a058e94253754a0bfe552d60ab822ad52c25b322c93b90d7479a91fe28da84ac038f8b295d523a4c2a18c08ed9c42' # ==> Controllerã®è¨å® # Devise::SessionsControllerãªã©ã®Deviseã®åã³ã³ããã¼ã©ã¼ã®è¦ªã¯ã©ã¹ã # config.parent_controller = 'DeviseController' # ==> Mailerã®è¨å® # Mailerã®fromã config.mailer_sender = '[email protected]' # Mailerã¯ã©ã¹ # ã«ã¹ã¿ã Mailerãå©ç¨ããå ´åã¯ãããå¤æ´ããã # 詳細ã¯ã035 ã¡ã¼ã©ã¼ãã«ã¹ã¿ãã¤ãºããããåç §ã # config.mailer = 'Devise::Mailer' # Devise::Mailerã®è¦ªã¯ã©ã¹ã # config.parent_mailer = 'ActionMailer::Base' # ==> ORMã®è¨å® # ORMããã¼ãããã # ActiveRcordã¨Mongoidããµãã¼ããã¦ããã require 'devise/orm/active_record' # ==> èªè¨¼å ¨è¬ã®è¨å® # èªè¨¼ãã¼ï¼ã¦ã¼ã¶ã¼ãèªè¨¼ããéã«å©ç¨ãããã¼ï¼ã # email以å¤ã®ãã¼ãå©ç¨ãããå ´åã«å¤æ´ããã # 詳細ã¯ã024 emailã®ä»£ããã«usernameã§ãã°ã¤ã³ãããããåç §ã # config.authentication_keys = [:email] # èªè¨¼ã«ä½¿ç¨ãããªã¯ã¨ã¹ããªãã¸ã§ã¯ãã®ãã©ã¡ã¼ã¿ã # config.request_keys = [] # 大æåå°æåãåºå¥ããªãèªè¨¼ãã¼ã # Userã®ä½æ/ä¿®æ£/èªè¨¼/æ¤ç´¢æã«å¤§æåå°æåãåºå¥ããªããã config.case_insensitive_keys = [:email] # 空ç½ãåé¤ããèªè¨¼ãã¼ã # Userã®ä½æ/ä¿®æ£/èªè¨¼/æ¤ç´¢æã«ç©ºç½ãåé¤ããã config.strip_whitespace_keys = [:email] # request.paramsã«ããèªè¨¼ãæå¹ã«ããã # `config.params_authenticatable = [:database]`ã¨ããã°DBèªè¨¼ï¼ã¡ã¼ã« + ãã¹ã¯ã¼ãï¼èªè¨¼ã®ã¿ãæå¹ã«ããã # config.params_authenticatable = true # HTTP Authã«ããèªè¨¼ãæå¹ã«ããã # `config.http_authenticatable = [:database]` ã¨ããã°DBèªè¨¼ã®ã¿ãæå¹ã«ããã # config.http_authenticatable = false # Ajaxãªã¯ã¨ã¹ãã«å¯¾ãã¦401ãè¿ãã # config.http_authenticatable_on_xhr = true # Basicèªè¨¼ã§å©ç¨ãããrealmã # config.http_authentication_realm = 'Application' # paranoidã¢ã¼ãã # ã¡ã¼ã«ã¢ãã¬ã¹ãç»é²ããã¦ãããã©ããã確èªããã®ãé²ãã # 詳細㯠https://github.com/heartcombo/devise/wiki/How-To:-Using-paranoid-mode,-avoid-user-enumeration-on-registerable # config.paranoid = true # userãsessionã«ä¿åããå¦çãã¹ãããããç®æã config.skip_session_storage = [:http_auth] # ã»ãã¥ãªãã£ã¼ã®ããèªè¨¼æã«CSRFãã¼ã¯ã³ãsessionããåé¤ããã # trueã ã¨ãµã¤ã³ã¤ã³ããµã¤ã³ã¢ããã§Ajaxã使ç¨ããå ´åããµã¼ãã¼ããæ°ããCSRFãã¼ã¯ã³ãåå¾ããå¿ è¦ãããã # config.clean_up_csrf_token_on_authentication = true # eager loadæã«ã«ã¼ãã£ã³ã°ããªãã¼ãããã # before_eager_loadããã¯ãå©ç¨ã # falseã«ããã¨ã¢ããªèµ·åãé«éã«ãªãããDeviseã®ãããã³ã°ããã¼ãããå¿ è¦ãããå ´åã¯æ£å¸¸ã«èµ·åã§ããªãã # config.reload_routes = true # ==> Database Authenticatableã¢ã¸ã¥ã¼ã«ã®è¨å® # ããã·ã¥åã®ã¬ãã«ã # ããã·ã¥åã«ã¯çµæ§æéããããã # bcryptï¼ããã©ã«ãã®ã¢ã«ã´ãªãºã ï¼ã®å ´åãã¬ãã«ã«å¿ãã¦ææ°é¢æ°çã«é ããªããä¾ãã°ã¬ãã«20ã§ã¯60ç§ç¨åº¦ãããã # ãã¹ãã®æã¯ã¬ãã«1ã«ãã¦é度ãä¸ããã # æ¬çªã§ã¯ã¬ãã«10以ä¸ã¯å©ç¨ãã¹ãã§ãªãã config.stretches = Rails.env.test? ? 1 : 12 # ããã·ã¥åããéã®pepperã # pepperã¯saltã¿ãããªãã¤ã # 詳細㯠https://stackoverflow.com/questions/6831796/whats-the-most-secure-possible-devise-configuration # config.pepper = '9a11b4eaf0250fec05630de0b518c3f63086fa403a8309d74408b3223d57a2312cef3ef746152f43c508da74b11cf21f982d9573ef552a186e36d83818129029' # emailå¤æ´æã«emailå¤æ´å®äºã¡ã¼ã«ãéä¿¡ããã # config.send_email_changed_notification = false # passwordå¤æ´æã«passwordå¤æ´å®äºã¡ã¼ã«ãéä¿¡ããã # config.send_password_change_notification = false # ==> Confirmableã¢ã¸ã¥ã¼ã«ã®è¨å® # confirmãªãã§ãã°ã¤ã³ã§ããæéã # ãããè¨å®ããã¨ä¸å®æéã¯confirmåã§ããã°ã¤ã³ã§ããããã«ãªãã # nilã«è¨å®ããã¨ç¡æéã«ãã°ã¤ã³ã§ããããã«ãªãã # ããã©ã«ã㯠0.daysãï¼confirmãªãã«ã¯ãã°ã¤ã³ã§ããªããï¼ # config.allow_unconfirmed_access_for = 2.days # confirmation_tokenã®æå¹æéã # ã¦ã¼ã¶ã¼ã¯ãã®æéå ã«confirmæ示ã¡ã¼ã«ã®ãªã³ã¯ãã¯ãªãã¯ããªãã¨ãããªãã # ããã©ã«ã㯠nilãï¼å¶éãªããï¼ # config.confirm_within = 3.days # ãµã¤ã³ã¢ããæã ãã§ãªããemailå¤æ´æã«ãConfirmã¡ã¼ã«ãéä¿¡ããã # unconfirmed_emailã«ã©ã ãå¿ è¦ã config.reconfirmable = true # confirmã®ãã¼ã # config.confirmation_keys = [:email] # ==> Rememberableã¢ã¸ã¥ã¼ã«ã®è¨å® # Sessionãåããã¾ã§ã®æéã # ããã©ã«ãã¯2.weeksã # config.remember_for = 2.weeks # ãã°ã¢ã¦ãæã«remember_tokenãæéåãã«ããã config.expire_all_remember_me_on_sign_out = true # cookieå©ç¨æã«æéã伸ã°ãã # config.extend_remember_period = false # cookieã«ã»ãããããªãã·ã§ã³ã # config.rememberable_options = {} # ==> Validatableã¢ã¸ã¥ã¼ã«ã®è¨å® # passwordã®é·ãã # Rangeã§æå®ããã®å ´åã¯6æåãã128æåã config.password_length = 6..128 # emailããªãã¼ã·ã§ã³ã§å©ç¨ããæ£è¦è¡¨ç¾ config.email_regexp = /\A[^@\s]+@[^@\s]+\z/ # ==> Timeoutableã¢ã¸ã¥ã¼ã«ã®è¨å® # ã¿ã¤ã ã¢ã¦ãæé # config.timeout_in = 30.minutes # ==> lockableã¢ã¸ã¥ã¼ã«ã®è¨å® # ããã¯æ¹æ³ # - failed_attempts: æå®åæ°ééããããã㯠# - none: èªåããã¯ã¯ãªãã§ããµã¼ã管çè ãæåã§ãã㯠# config.lock_strategy = :failed_attempts # ã¢ã³ããã¯ã®ãã¼ # config.unlock_keys = [:email] # ã¢ã³ããã¯æ¹æ³ # - email: ã¡ã¼ã«ã§ã¢ã³ããã¯ã®ãªã³ã¯ãéä¿¡ # - time: æ°æéå¾ã«ã¢ã³ããã¯ï¼config.unlock_inã¨ä¸ç·ã«ä½¿ãï¼ # - both: emailã¨timeã®ä¸¡æ¹ # - none: èªåã¢ã³ããã¯ã¯ãªãã§ããµã¼ã管çè ãæåã§ã¢ã³ãã㯠# config.unlock_strategy = :both # ããã¯ã¾ã§ã®åæ° # config.maximum_attempts = 20 # ã¢ã³ããã¯ã¾ã§ã®æéï¼`config.unlock_strategy = :time`ã®å ´åï¼ # config.unlock_in = 1.hour # ããã¯åã«è¦åãã # config.last_attempt_warning = true # ==> Recoverableã¢ã¸ã¥ã¼ã«ã®è¨å® # # ãã¹ã¯ã¼ããªã»ããæã«ãã¼ã«ãªãã«ã©ã ã # config.reset_password_keys = [:email] # ãã¹ã¯ã¼ããªã»ããã®æå¹æéã config.reset_password_within = 6.hours # ãã¹ã¯ã¼ããªã»ããå¾ã«èªåãã°ã¤ã³ã # config.sign_in_after_reset_password = true # ==> devise-encryptable gemã®è¨å® # bcrypt以å¤ã®ããã·ã¥åã¢ã«ã´ãªãºã ã # devise-encryptable gemã®ã¤ã³ã¹ãã¼ã«ãå¿ è¦ã # bcrypt以å¤ã®ã¢ã«ã´ãªãºã ã¯:sha1ã:sha512ã:clearance_sha1ã:authlogic_sha512ã:sha1ãªã©ã # config.encryptor = :sha512 # ==> Scopeã®è¨å® # Scopeç¨ã®ãã¥ã¼ãåªå çã«ä½¿ãããã«ãªãã # trueã«ããã¨`devise`åå空éã®ãã¥ã¼ã§ã¯ãªãã`users`ãªã©ã®Scope対å¿ã®ãã¥ã¼ãå©ç¨ããã # ããã©ã«ãã¯é«éåã®ãã`false`ã«è¨å®ããã¦ããã # 詳細ã¯ã023 è¤æ°ã¢ãã«ãå©ç¨ããããåç §ã # config.scoped_views = false # ããã©ã«ãã®Scopeã # é常ã§ããã°userã«ãªãã # config.default_scope = :user # ãã°ã¢ã¦ãæã«å ¨ã¦ã®Scopeã§ã®ãã°ã¢ã¦ãã¨ããã # falseã®å ´åã¯/users/sign_outã§ãã°ã¢ã¦ãããå ´åãuser scopeã ããã°ã¢ã¦ãã«ãªãã # config.sign_out_all_scopes = true # ==> Navigationã®è¨å® # ããã²ã¼ã·ã§ã³ã¨ãã¦æ±ããããã©ã¼ãããã®ãªã¹ãã # config.navigational_formats = ['*/*', :html] # ãã°ã¢ã¦ãæã®HTTPã¡ã½ãã config.sign_out_via = :delete # ==> OmniAuthã®è¨å® # OmniAuthã®è¨å®ã # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' # ==> Wardenã®è¨å® # Wardenã®è¨å®ã # strategy追å ãããfailure_appå¤æ´ãããã # # config.warden do |manager| # manager.intercept_401 = false # manager.default_strategies(scope: :user).unshift :some_external_strategy # end # ==> Mountable Engineã®è¨å® # Mountable Engineã§ä½¿ãéã®routeråã # config.router_name = :my_engine # # OmniAuthã®pathã # OmniAuthãå©ç¨ããå ´åã«è¨å®ããã # config.omniauth_path_prefix = '/my_engine/users/auth' # ==> Turbolinksã®è¨å® # Turbolinksãå©ç¨ãã¦ããå ´åããªãã¤ã¬ã¯ããæ£ããåä½ãããããã«Turbolinks::Controllerãincludeããã # # ActiveSupport.on_load(:devise_failure_app) do # include Turbolinks::Controller # end # ==> Registerableã¢ã¸ã¥ã¼ã«ã®è¨å® # ãã¹ã¯ã¼ãå¤æ´å¾ã«èªåçã«ãµã¤ã³ã¤ã³ãããã # config.sign_in_after_change_password = true end
ãªã¼ã³ã§ã¢ã¸ã£ã¤ã«ã§ã¢ãã¢ããªTwitterBotéçº
- ã¯ããã«
- é¡å¤ããBotã®ç´¹ä»
- mofmofããã®ç ä¿®
- ãªã¼ã³éçºã®æ¦è¦
- ã¢ã¤ãã¢åºã
- ãªã¼ã³ãã£ã³ãã¹ä½æ
- ã¤ã³ã»ãã·ã§ã³ãããä½æ
- ã¹ãã¼ãªã¼åºã
- MVPéçº
- KPTã§ãµãããã
- ãããã«
ã¯ããã«
å æãããä¸è©±ã«ãªã£ã¦ããmofmofããã®ç ä¿®ã§ãé¡ãå¤ãã¦éã¶TwitterBotãéçºãã¾ããã
ãã®è¨äºã¯éçºããTwitterBotã®ç´¹ä»ã¨ãmofmofããã§å¦ãã ç ä¿®å 容ã®ã¾ã¨ãã§ãã
é¡å¤ããBotã®ç´¹ä»
ãé¡å¤ããBotãã¯ãAIãçã¿åºããå®å¨ããªã人ç©ã®é¡ããAIã«ããé¡åææè¡ã§ã¦ã¼ã¶ã¼ã®é¡ã«åæãã¦ãé¡ãå¤ãã¦éã¶TwitterBotã§ãã
ãããªæãã§é¡å¤ããBotï¼@kaokaeru_botï¼ã«äººç©ç»åãã¡ã³ã·ã§ã³ããã¨ãé¡ãå¤ããç»åããªãã©ã¤ãã¦ããã¾ãã
é«ã«ãªã£ã¦ã¾ããï¼(ΦÏΦ) pic.twitter.com/Nk1XcCTr33
— é¡å¤ããbot(ΦÏΦ) (@kaokaeru_bot) 2019å¹´12æ25æ¥
ãã¢ã¤ãã«ã«ãã¦ï¼ãããé«é¢ã«ãã¦ï¼ãã®ããã«ããªãããé¡ãæå®ãããã¨ãã§ãã¾ãã
æãããªæãã®ããªã¢ã«ãã¼ãã£ã«Youtuberã ã¨ããé¡ãå¿ååããWebãµã¼ãã¹ãå人éçºããã®ã§ããããã¡ããã¢ã¤ãã¢ã®ãã¼ã¹ã«ãªã£ã¦ãã¾ãã
mofmofããã®ç ä¿®
èªåã¯ããªã¼ã©ã³ã¹ã¨ãã¦mofmofããã«ãä¸è©±ã«ãªã£ã¦ããã®ã§ãããã¾ã ã¾ã çµé¨ãæµ ããã¨ããã£ã¦mofmofããã®ç ä¿®ãåãããã¦ããã ããã¨ãã§ãã¾ããï¼
mofmofããã§ã¯ãªã¼ã³/ã¢ã¸ã£ã¤ã«ã«é¢ãã10ç¨åº¦ã®ç ä¿®ãã社é·ã®ã¯ãã±ãããã«ããè¬ç¾©/ã¯ã¼ã¯ã·ã§ããã®å½¢å¼ã§åãããã¨ãã§ãã¾ããããã¦ç ä¿®ã§å¦ãã ãã¨ã®å®è·µã®å ´ã¨ãã¦ãã¡ã³ã¿ã¼ããã®æå°ãåããªããä¸äººã§ãããã¯ãéçºãè¡ãã¾ããé¡å¤ããBotã¯ããã§éçºãããããã¯ãã§ãã(é常ã¯1ã¶æããã¦Railsã¢ããªã®éçºãè¡ãããã§ãããèªåã®å ´åã¯Railsã¢ããªéçºã®çµé¨ããã£ãã®ã¨ä»ã®ä»äºã§ãã¾ãæéãåããªããã ã£ãã®ã§ãTwitterBotã®éçºãããã¦ããã ãã¾ããã)
ããããã¯ç ä¿®ã§å¦ãã ãã¨ãèªåãªãã«ã¾ã¨ãã¦ããã¾ãã
ãªã¼ã³éçºã®æ¦è¦
ãªã¼ã³éçºã«ã¯ãå ¨ã¦ã¯ä»®èª¬ã§ãããã¨ããåæãããã¾ãã
ãããã¯ãéçºãå§ããéã«ãªã¼ã³ãã£ã³ãã¹(å¾è¿°)ãªã©ã®ãã¼ã«ã使ã£ã¦ãã¿ã¼ã²ããã¨ãã顧客ã解決ããã課é¡ãæ確ã«ãã¦ããã¾ãããããããã§æ³å®ãã¦ãã顧客ã課é¡ã¯ãã ã®ä»®èª¬ã§ããèªåãã©ãã ãè¯ããããã¯ãã ã¨æã£ã¦ããå®éã«ã¯ãããªãã®ã欲ããã£ã¦ãã人ã¯ã©ãã«ãåå¨ããªãããããã¾ããããã®ããå®éã«ä½¿ã£ã¦ãããããããã¯ããéçºããããã«ã¯ããã®ä»®èª¬ãæ£ãããã©ãããã¾ãæ¤è¨¼ããå¿ è¦ãããã¾ãã
ãªã¼ã³éçºã§ã¯ä»®èª¬ãæ¤è¨¼ããããã«MVP(Minimum Viable Product)ãéçºãã¾ããMVPã¨ã¯æå°éã®æ©è½ã ããåããã仮説ãæ¤è¨¼ããããã®ãããã¯ãã§ããMVPãä½ã£ã¦ãå®éã«ã¦ã¼ã¶ã¼ã«ä½¿ã£ã¦ããã£ã¦ãã£ã¼ãããã¯ãåãåããããããå¦ãã ãã¨ããã¼ã ã§å¦ç¿ããMVPãä¿®æ£ãã¾ãããã®Build(æ§ç¯) -> Measure(測å®) -> Learn(å¦ç¿)ã®ã«ã¼ããç¹°ãè¿ããã¨ã§ã仮説æ¤è¨¼ãè¡ã£ã¦ããã¾ãã常ã«ã¦ã¼ã¶ã¼ããå¦ã³ä¿®æ£ãã¦ããã®ã§ãMVPãæçµçã«ã©ãããå½¢ã«ãªããã¯äºæ³ãã¤ãã¾ããã
MVPãä½ãéã«ã¯ä»¥ä¸ã®ãã¨ã«æ°ãã¤ãã¾ãã
- æ©è½ãæå°éã«ãããæ©è½ãä½ãããã¦ãã¾ãã¨ç¡é§ãªã³ã¹ããããã¦ãã¾ãããã³ã¢æ©è½ãã¼ããã¦ãã¾ãã仮説æ¤è¨¼ãè¡ãããã«ã¯æ©è½ã¯æå°éã§ãããMust-haveã ãä½ãããã«ãã¦Nice-to-haveã¯ã¹ã±ã¼ã«æã«å¿ è¦ã«ãªã£ã¦ããä½ãã°ããã
- 仮説æ¤è¨¼ã«æ³¨åããããã®ãã顧客ã¨ã®å¯¾è©±ãéè¦ããããªã¼ã³ã§ã¯ãã¼ã±ãã£ã³ã°ãå«ãã¦ãå ¨ã¦ã¯æ¤è¨¼ã«ããå¦ã³ãå¾ãããã«è¡ãè¡çºã«ãªãã顧客ã¨èª²é¡ã®æ¤è¨¼ã¯æåªå äºé ã
- æå°éã®ã³ã¹ãã§ä½ãããªã½ã¼ã¹ã¯æéãªã®ã§ãªã½ã¼ã¹ãå°½ããåã«ä»®èª¬æ¤è¨¼ããå¿ è¦ãããããã®ããã«ã¯ä»®èª¬æ¤è¨¼ã«ã¼ãã¯ç´ æ©ãåãã
- ã¢ã¼ãªã¼ã¢ããã¿ã«åãã¦ä½ããå ¨å¡ã«åãã¦ä½ãã¨èª°ã欲ãããªããã®ãã§ãã¦ãã¾ããå ¨å¡ã«å¥½ã¾ãããã®ã§ã¯ãªããä¸é¨ã«ç±ççã«æããããã®ãä½ãã
- ã¾ãã¯èª²é¡ã®è³ªãä¸ãããã½ãªã¥ã¼ã·ã§ã³ã®è³ªãä¸ããã®ã¯ãã®å¾ã§ãªãã¨ç¡æå³ã課é¡ãééã£ã¦ãããä½ãç´ãã«ãªãã
MVPã¯ãããã¯ãã§ã¯ãªãããªãããä½ãå ´åãããã¾ããæåãªã¨ããã§ã¯Dropboxã®ãã¢åç»çãããã¾ãããmofmofããã®å ´åã¯å®éã«è§¦ãããããã¯ããä½ãã¾ãã
åè: リーン・スタートアップとMVP/lean-startup-mvp - Speaker Deck
æ¬ã ã¨ãªã¼ã³ã»ã¹ã¿ã¼ãã¢ããã®éæ¬ãæåã§ãããå®è·µæ¹æ³ã«ã¤ãã¦è©³ããæ¸ãã¦ãªãã¦èªåã«ã¯é£ããã£ãã§ããä¼æ¥ã®ç§å¦ãèªã¿ãããã¦ããã£ãã§ãã ãã¨æ£ç¢ºã«ã¯ãªã¼ã³ã¨éãããããã¾ããããBasecampã®Getting Realã¨å°ããªãã¼ã ã大ããªä»äºãRailsã¨ã³ã¸ãã¢ã«ã¯é¦´æã¿ããã£ã¦ããããã§ãã
ã¢ã¤ãã¢åºã
ã¢ã¤ãã¢åºãã®åºæ¬
ä¸çªåãã¯ãã©ããªãããã¯ããä½ãã®ãã¢ã¤ãã¢åºããè¡ãã¾ãã
ã¢ã¤ãã¢åºãã§ã¯é£æ³ãåºæ¬ã«ãªãã¾ãã人ã¯ãªã«ããªãã¨ããããã¢ã¤ãã¢ãåºããã¨ã¯ã§ãã¾ãããå¿ ãä½ãããã®æããããå ã«ãã¦çºæ³ãè¡ãã¾ãã
ãã¾ãã¢ã¤ãã¢åºããããããã«ã¯ãã®æããããä½ããã®å½¢ã§èªåã«ä¸ããå¿ è¦ãããã¾ããä¾ãã°ãã¿ã¦ã³ã¦ã©ããã³ã°æ³ãã¨ããçºæ³æ³ãããã¾ããè¡ä¸ã«åºã¦äººããã®ã観å¯ãã¦ã観å¯ãããã®ãã¡ã¢ãã¦ããã¾ããããã¦è¡ä¸ãæ©ããéã®è¨æ¶ãã¡ã¢ãå ã«æ°ããã¢ã¤ãã¢ãçºæ³ãã¾ããããã§ã¨ãã¡ã¢ã¯ããã¹ãã«éå®ããã¾ãããæãããã«ãªãã°ããã®ã§ã¤ã©ã¹ãã§ãOKã§ãã
å ·ä½çãªã¢ã¤ãã¢åºãã®æ¹æ³ã«ã¤ãã¦ã¯ãã¡ãã®ãçºæ³ããæè¡ããããããããã¾ããã30ã®çºæ³æ³ãç¶²ç¾ çã«æ¸ãã¦ããã¾ãã
æ¬ ç¹åææ³ã§ã¢ã¤ãã¢åºã
èªåã®å ´åã¯ä»¥åä½ã£ãããªã¢ã«ãã¼ãã£ã«Youtuberããæ¹åãããã¨ããæãããã£ãã®ã§ããããã¯ãã®æ¹åæ¡ãçºæ³ãããæ¬ ç¹åææ³ãã¨ããæ¹æ³ãåèã«ãã¾ãããã¾ããããã¯ãã®æ¬ ç¹ãåæãã¦ãããããããæ¹åæ¡ãçºæ³ãã¦ããçºæ³æ³ã§ãã
ããªã¢ã«ãã¼ãã£ã«Youtuberãã¯åç»ãã¢ãããã¼ãããã¨æ¶ç©ºã®äººç©ã®é¡ã«å¤æãã¦ãããWebãµã¼ãã¹ã§ãããã¡ãã®æ¬ ç¹ãåæãã¦ããã¾ãã
æ¬ ç¹ã¨ãã¦ã¯
- åç»ã«ãµã¤ãºå¶é/æéå¶éããããã使ãã«ãã
- åç»ã®é¡å¤æã«æéãããã
- ãµã¤ã³ã¢ãããåç»ä½æã§é¢è±ãã¦ãã¾ã人ãå¤ã
- å¤æããåç»ãå ±æããæ段ããªã
æ¹åæ¡ã¨ãã¦ã¯
- åç»ã§ã¯ãªãç»åã«ããã°ããµã¤ãº/æéå¶éã¯ãªããªã
- åç»ã§ã¯ãªãç»åã«ããã°ãçæéã§å¦ç¿ã§ãã
- Webãµã¼ãã¹ã§ã¯ãªãTwitterBotã«ããã°ãé¢è±ãã¤ã³ããæ¸ã
- Webãµã¼ãã¹ã§ã¯ãªãTwitterBotã«ããã°ããã®ã¾ã¾å ±æã§ãã
ãããªæãã§ããªã¢ã«ãã¼ãã£ã«Youtuberãã®TwitterBotçãä½ã£ã¦ãåç»ã®ä»£ããã«ç»åãå¤æããã°ãã£ã¨ä½¿ã£ã¦ããããããã«ãªãã®ã§ã¯ï¼ã¨çºæ³ãã¦ããã¾ããã
è¯ãã¢ã¤ãã¢ã®ãã¤ã³ã
ãªã¼ã³éçºã«ããã¦è¯ãã¢ã¤ãã¢ã«ã¯ä»¥ä¸ã®ãããªãã¤ã³ããããã¾ããã§ããã ããããããããã¦ããã¾ãã
- ä¸è¨ã§è¡¨ããã¢ã¤ãã¢ãè¯ãã¢ã¤ãã¢ãã¤ã³ãã¯ããä¸ããããã«ã¯ãä¸è¨ã§è¡¨ããªãã¨ãããªãã
- ç¾å®ã®èª²é¡ã解決ããã¢ã¤ãã¢ãè¯ãã¢ã¤ãã¢ãæ¶ç©ºã®èª²é¡ã解決ãã¦ã誰ã使ã£ã¦ãããªãã
- èªåã®èª²é¡ã解決ããã¢ã¤ãã¢ãè¯ãã¢ã¤ãã¢ã顧客 = èªåã«ãªãã®ã§ã課é¡ãæ·±ãç解ã§ããã
- æè¡ããªãã³ã§ã¯ãªã課é¡ããªãã³ãªã¢ã¤ãã¢ãè¯ãã¢ã¤ãã¢(å ´åã«ãã?)
é¡å¤ããbotã¯ã©ã¡ããã¨ããã¨èª²é¡ãããã§ã¯ãªãæè¡ãããã®æè¡ããªãã³ãªã®ã§ãããå人éçºã¨ãå ´åã«ãã£ã¦ã¯ããããããæ¹ãã¢ãªãªããã§ãã
ãªã¼ã³ãã£ã³ãã¹ä½æ
ãªã¼ã³ãã£ã³ãã¹ã®åºæ¬
ã¢ã¤ãã¢åºããçµãã£ããããã®ã¢ã¤ãã¢ããªã¼ã³ãã£ã³ãã¹ã«ã¾ã¨ãã¾ããã¢ã¤ãã¢åºããçºæ£ã§ããªã¼ã³ãã£ã³ãã¹ä½æãåæã§ããçºæ£ã¨åæã¯åãã¦è¡ãã¾ãã
ãªã¼ã³ãã£ã³ãã¹ã§ã¯ãããªæãã§ãã£ã³ãã¹ãç¨æãããã®ã§ã9ã¤ã®é ç®ãåãã¦ããã¾ãã
é ç®ãåãã¦ãããã¨ã§ãã¸ãã¹ã¢ãã«ãæ´çã§ãã¦ãå®éã«éçºãã価å¤ããããã©ãããåæã§ãã¾ãã
ãªã¼ã³ãã£ã³ãã¹ã®è¯ãç¹ã¯ä»¥ä¸ã®ã¨ããã§ãã
- ãã¸ãã¹ã¢ãã«ãæ´çã§ããããã¸ãã¹ã¢ã¤ãã¢ããããã§ããããã«ãªã
- ãã¸ãã¹ã¢ãã«ãåæã§ãããã©ãã«å¼±ç¹ãããããããã
- ç°¡åã«ä½ãããäºæ¥è¨ç»æ¸ã¯ä½ãã®å¤§å¤ã ãã©ããªã¼ã³ãã£ã³ãã¹ãªã10åã§ä½ããã
åè: リーンキャンバスの作り方/how-to-make-lean-canvas - Speaker Deck
ãªã¼ã³ãã£ã³ãã¹ä½æ
é¡å¤ããbotã®ãªã¼ã³ãã£ã³ãã¹ã¯ãããªæãã«ãªãã¾ããã
è¦ã«ããå ´åã¯ãã¡ã -> https://www.mof-canvas.com/canvases/41
ãã®ä¸ã§ãç¹ã«éè¦ãªé ç®ã課é¡ã¨é¡§å®¢ã»ã°ã¡ã³ãã§ãããããä»åã®é¡å¤ããbotã¯èª²é¡ã¨é¡§å®¢ã»ã°ã¡ã³ãããªããªãåºã¾ãã¾ããã§ãããã¨ããã®ãé¡å¤ããbotã¯ãèªåã®é¡ãå¤ãã¦ãããã·ã§ã¢ãã¦æ¥½ããã§ããããã¨ãæ³å®ãã¦ãã¾ããã楽ãããã¨ããéã¶ãã¨ããã®ãã©ããã£ã¦èª²é¡ã«ããã°ããã®ãããã¾ããã§ãããã¡ã³ã¿ã¼ããã«ç¸è«ããã¨ãããä¾ãã°å¥³åé«çãã¿ã¼ã²ããã«ãããªãæãæ½°ãããã®ãããããªãããã¤ã³ãã«ã¨ã³ãµã¼ãã¿ã¼ã²ããã¨ãããªããã®äººéã¯ãã©ãã¯ã¼ãå¢ãããããããããªãããã¡ãã¨æ·±å ãããã°åºã¦ãããã¨ããããã¼ã¨ã¢ããã¤ã¹é ãã¾ããã
ãã以å¤ã«ããã¤ã¬ãã«ã³ã³ã»ããã¯1ã¤ã«çµã£ãã»ããè¯ãããã¨ãããã£ãã«ã¨ãã¦ã¤ã³ãã«ã¨ã³ãµã¼ããã«ä½¿ã£ã¦ãããã®ããããããã¨ãããã£ã¼ãããã¯ããããã¤ã¤ããã«ãã©ãã·ã¥ã¢ãããã¦ããã¾ããã
ãªã¼ã³ãã£ã³ãã¹ä½æã«ã¯mof-canvasã¨ãããµã¼ãã¹ã使ãã¾ããããã¡ãã¯mofmofã®ç¤¾å¡ãããç ä¿®ã§ä½æãããµã¼ãã¹ã«ãªãã¾ãã使ããããããä½æããå ¬éã¾ã§ç°¡åã«ã§ããã®ã§ããããã§ãã
ã¤ã³ã»ãã·ã§ã³ãããä½æ
ã¤ã³ã»ãã·ã§ã³ãããã®åºæ¬
ã¤ã³ã»ãã·ã§ã³ãããã¯ã10ã®è³ªåã«çãããã¨ã§ããã¸ã§ã¯ãã®å ¨ä½åãæ確ã«ãã¦ãããã¸ã§ã¯ãã®ç®çããã¼ã ã¡ã³ãã¼éã§åæããããã®ããã¥ã¡ã³ãã§ãã
ãããã¯ãéçºãããéã顧客èªèº«ãå¿ è¦ãªãã®ãç確ã«è¡¨ç¾ã§ããããã§ã¯ããã¾ããã顧客ã«è¨ããããã®ããã ä½ãã ãã ã¨ãã ãã欲ãããªããã®ãä½ã£ã¦ãã¾ãããããã¾ããããããã¯å ¨ãè¦å½éããªãã®ãä½ã£ã¦ãã¾ãããããã¾ããã顧客ã«è¨ããããã®ããªãã¨ãªãæ³åã§ä½ãã®ã§ã¯ãªãã顧客ãæã価å¤ãå®ç¾ãããã¨ã大åã§ãã価å¤ãå®ç¾ããããã«ã¯ãéçºãå§ããåã«ããããããã¸ã§ã¯ãã®ç®çãä½ãªã®ããæ確ã«ãã¦ããããåæãã¦ããå¿ è¦ãããã¾ããã¤ã³ã»ãã·ã§ã³ãããã¯ãã®ããã®ããã¥ã¡ã³ãã§ãã
ã¤ã³ã»ãã·ã§ã³ãããä½ææã®ãã¤ã³ã
- åæã®ããã»ã¹ã大åããªãã¨ãªãåæããã®ã§ã¯ãªããã¡ããã¨ã¡ã³ãã¼éã§è°è«ããã¦åæããã
- æçµçã«ã¯èªåã§ãããã¯ãã®ä¾¡å¤ã説æã§ããããã«ããã
- æ¬æ¥ã¯ãããã¯ããªã¼ãã¼ãä½ããã®ãå®éã«ã¯éçºè ãä½ã£ã¦ä¸»ä½ã¨ãªã£ã¦é²ããã»ããä¸æãããã
- ä¸åº¦ä½ã£ã¦çµããã§ã¯ãªãããã¨ããæ¯ã«è¦è¿ãã¦æ´æ°ãã¦ããã
åè: インセプションデッキの作り方/how-to-make-inception-deck - Speaker Deck
ã¤ã³ã»ãã·ã§ã³ãããä½æ
æ¬æ¥ã¯11æã®ã¹ã©ã¤ããåãã¾ãããä»åã¯ç¹ã«å¤§åãª4æãåãã¾ããã
ãã¬ã¼ããªãã»ã¹ã©ã¤ãã¼ã§ã¯é常ã¯ã¹ã³ã¼ã/äºç®/æé/å質ã®4ã¤ã®ã¹ã©ã¤ãã¼ã使ãã¾ãããã ãå質ãã¯å®ç¾©ãææ§ã«ãªããã¡ã§ããä¿å®æ§ã®é«ããæãã®ãï¼è¦ãç®ã®ç¶ºéºããæãã®ãï¼ãã°ã®å°ãªããæãã®ãï¼ããå質ããä½ãæããã¯èªæã§ã¯ããã¾ãããããã§ä»åã¯å質ã®é ç®ã¯å¤ãã¾ããã
ç ä¿®æéã¯æ±ºã¾ã£ã¦ããã®ã§æéã¯MAXã«ãã¦ãäºç®ã«å¤§ããªç¸ãããªãã®ã§ã»ã¼MINã«ãã¦ãã¾ãã
ã¤ã³ã»ãã·ã§ã³ãããã§ã¯åæã®ããã»ã¹ã大åã«ãªãã¾ããä»åã¯å¤åçã«ãªãã¾ããã¡ã³ã¿ã¼ããã«POã¨ãã¦ã¤ã³ã»ãã·ã§ã³ããããä½ã£ã¦ãããããããè°è«ããªããåæãã¦ãã®å½¢ã«ãã¦ããã¾ãããä¾ãã°æåã¯ãããããã®é¡ã¢ãã«ãç¨æãããã¨ããã®ããããªã¹ãã«å ¥ã£ã¦ããã®ã§ãããããã¯MVPã«ã¯å¿ é ã§ã¯ãªãã®ã§ã¯ï¼ã¨ãããã¨ã§ãããªããã¨ãªã¹ãã«ç§»ããããã¾ããã
ã¹ãã¼ãªã¼åºã
ã¹ãã¼ãªã¼åºã
ã¤ã³ã»ãã·ã§ã³ãããã®ä½æãçµãã£ãããã¦ã¼ã¶ã¼ã¹ãã¼ãªã¼åºããè¡ãã¾ãã
ã¦ã¼ã¶ã¼ã¹ãã¼ãªã¼ã¨ã¯ã¦ã¼ã¶ã¼ãå®ç¾ããããã¨ãç°¡æ½ã«ã¾ã¨ããæç« ã§ããã¦ã¼ã¶ã¼ã¹ãã¼ãªã¼ãä½ãéã¯ä»¥ä¸ã®ãã¤ã³ãã«æ°ãã¤ãã¾ãã
- ã¦ã¼ã¶ã¼ã«ã¨ã£ã¦ã®ä¾¡å¤ã«éããç½®ãããã«ãã¦ã¼ã¶ã¼ç®ç·ã§æ¸ã
INVEST
ãæºããã¦ãã- Independent: åã¹ãã¼ãªã¼ãä»ã®ã¹ãã¼ãªã¼ã«ä¾åããåä½ã§æ©è½ãã
- Negotiable: ãã£ã¡ãä»æ§ããããã«ãå®è£ æ¹å¼ã«ã¤ãã¦äº¤æ¸å¯è½ã§ãã
- Valuable: 価å¤ãæä¾ã§ãã
- Estimable: è¦ç©ããå¯è½ã§ãã
- Sized appropriately: é©åãªãµã¤ãºã§ãã
- Testable: ãã¹ãå¯è½ã§ãã(åãå ¥ãæ¡ä»¶ããã)
åè: ユーザーストーリーとは?
å®éã®ã¹ãã¼ãªã¼åºãã§ã¯ã¡ã³ã¿ã¼ããã¨ä¸ç·ã«ä»ç®ã«ã¹ãã¼ãªã¼ãæ¸ãåºãã¦ããã¾ãããä¸éãã¹ãã¼ãªã¼ãåºãåã£ãããã¹ãã¼ãªã¼ã«æãããªãã確èªããå¾ã«Pivotal Trackerã«ããã¯ãã°ã¢ã¤ãã ã¨ãã¦ç»é²ãã¦ããã¾ãã
è¦ç©ãã
次ã«ç»é²ããã¹ãã¼ãªã¼ãè¦ç©ããã¾ãã
è¦ç©ããã¨ãã¦ã¹ãã¼ãªã¼ã«ã¹ãã¼ãªã¼ãã¤ã³ããä»ãã¦ããã¾ããmofmofããã§ã¯ãRailsã§ãã¼ãã«ã«1ã¤ã«ã©ã ã追å ãã¦ããã¥ã¼çãåããã¦å¤æ´ããããåºæºãµã¤ãºã®1ã¨ãã¦ããã®ã§ãããã¨æ¯ã¹ãç¸å¯¾çãªãã¤ã³ããåã¹ãã¼ãªã¼ã«ä»ãã¦ããã¾ããçæ³æ¥ã®ãããªçµ¶å¯¾ãµã¤ãºã使ãã±ã¼ã¹ãããããã§ãããã¹ãã¼ãªã¼ãã¤ã³ãã®ãããªç¸å¯¾ãµã¤ãºã使ãã»ãã主æµã®ããã§ãã
注æãã¹ãç¹ã¨ãã¦è¦ç©ããã¯ããã¾ã§ãè¦ç©ããã§ããããã¾ããã確å®ãªäºæ¸¬ã§ã¯ããã¾ããããã³ãããã¡ã³ãã§ãããã¾ããã
åè: 見積もり/agile-estimation - Speaker Deck
å®éã®è¦ç©ããã§ã¯ã¡ã³ã¿ã¼ããã¨ãã£ããããæ°åãç¨ãã¦ãã©ã³ãã³ã°ãã¼ã«ã¼ãè¡ãè¦ç©ããã¾ããã
åè: プランニングポーカーのやりかた – Ryuzee.com
ã¹ã³ã¼ãåã
è¦ç©ãããçµããã¨éçºã«ã©ããããã®æéãããããããè¦ãã¦ãã¾ããããã·ãã£ã¯ããã¸ã§ã¯ããé²ãã°è¨ç®ã§ããããã«ãªãã®ã§ãããããã¸ã§ã¯ãéå§æç¹ã ã¨ããããªãã®ã§ä»åã¯çµé¨åçã«é©å½ãªæ°åãå©ç¨ãã¦ãã¾ããå°ããªãããã¯ããªã®ã§ã¹ãã¼ãªã¼ã¯5ã¤ç¨åº¦ã¨ããªãå°ãªãã ã£ãã®ã§ãããããã§ããªãªã¼ã¹æ¥(ç ä¿®ã®æçµæ¥)ã«ã¯éã«åããªãæãã§ããã
ãããããªãªã¼ã¹æ¥ã«éã«åãããã«ã¹ã³ã¼ããåã£ã¦ããã¾ãããã®ããã¸ã§ã¯ãã¯ç ä¿®æéã決ã¾ã£ã¦ããããããã¬ã¼ããªãã¹ã©ã¤ãã¼ã®æéã¯MAXã«è¨å®ããã¦ãã¾ãããªãªã¼ã¹æ¥ã¯ãããã¾ãããäºç®ãå¢ããã¦éçºé度ãä¸ããããããã¸ã§ã¯ãã§ããªãã®ã§ã¹ã³ã¼ããåãããããã¾ããã
æåã¯èªåã«ã¯å ¨ã¦ã®æ©è½ãå¿ é ã«æããã®ã§ãåãã®ã¯ç¡çãªããããªããã¨æãã¾ããããããã¡ã³ã¿ã¼ããã®ã¢ããã¤ã¹ãå ã«ç²¾æ»ãã¦ããã¨ãã¦ã¼ã¶ã¼ã¯é¡ãå¤æã§ãããã¨ããã¹ãã¼ãªã¼ã¯ãã£ã¨ç´°ããå解ã§ãããã¨ãããã£ã¦ãã¾ããã¹ãã¼ãªã¼ãç´°ããå解ãã¦ãããã¡ã«ãå解ããã¦ã§ãããã¦ã¼ã¶ã¼ã¯ãªãããé¡ãæå®ã§ãããã¨ããã¹ãã¼ãªã¼ãå®ã¯MVPã«å¿ é ã§ã¯ãªããã¨ãå¤æãã¾ããMPVã¯å®ç¨æå°éã®ãããã¯ãã§ãããã®ãããã¯ããæä¾ãã価å¤ã¯ãé¡ãå¤ãã£ã¦ããããã¿ããªã¨æ¥½ããããªã®ã§ãããªãããé¡ãæå®ã§ãããã¨ããã¹ãã¼ãªã¼ã¯å¿ ãããå¿ é ã§ã¯ããã¾ããããã ãªã«ãã«é¡ãå¤ããã ãã§ãç®çã¯éæã§ãã¾ãã
ãããªæãã§å¿ é ã«è¦ãããã©å®éã«ã¯å¿ é ã§ã¯ãªãã¹ãã¼ãªã¼ãã¹ã³ã¼ãå¤ã«ãã¦ãã£ã¦ããããããªãªã¼ã¹æ¥ã«éã«åãããã«ã¹ã³ã¼ããåãã¾ãããï¼çµå±æå¾æéãä½ã£ãã®ã§ããã®æã«ã¹ã³ã¼ãå¤ã«ããã¹ãã¼ãªã¼ã®ããã¤ãã¯å®è£ ããã®ã§ãããããã¯ããã§ããã®ããªã¼ã¨æãã¾ããï¼
MVPéçº
ããã¾ã§ã§éçºã®æºåã¯æ´ã£ãã®ã§ãããããå®éã«MVPã¨ãªããããã¯ããéçºãã¦ããã¾ãã
ä»åä½æããããã°ã©ã ã¯ãã£ãã2ã¤ã«åãããã¾ãã1ã¤ã¯TwitterAPIãå©ç¨ãã¦ã¡ã³ã·ã§ã³ããç»åãåå¾ãã¦ãªãã©ã¤ãè¿ãBotå´ã®ããã°ã©ã ããã1ã¤ã¯ç»åã®é¡ãå¤æããAIå´ã®ããã°ã©ã ã§ãã
Botå´ã®ããã°ã©ã ä½æ
TwitterAPIã使ãããã«APIç³è«ããã¾ããæè¿ç³è«ãå³ãããªã£ãã¨èãã¦ããã®ã§ãå®ã¯ãããä¸çªä¸å®ã§ãããã§ããã®è¨äºãåèã«ç³è«ãã¦ã¿ãã¨ããããªã審æ»ã¯éãã¾ããã
ç³è«ããTwitterAPIã使ã£ã¦Botå´ã®ããã°ã©ã ãæ¸ãã¦ããã¾ããé¡å¤ããBotã§ã¯ã¡ã³ã·ã§ã³ãããç»åãå å·¥ãããããã¡ã³ã·ã§ã³ãç£è¦ããå¿ è¦ãããã¾ããAccount Activity APIã¨ããã®ã使ãã°Webhookã§éç¥ãåãåãããããã®ã§ãããå¥éç³è«ãå¿ è¦ã ã£ããçµæ§é¢åãªãã¨ãå¤ãããã§ãããªã®ã§åç´ã«Rubyããã»ã¹ã常é§ããã¦ãã¡ã³ã·ã§ã³ãæ¥ã¦ããªãã確èªããããã«REST APIããã¼ãªã³ã°ããå½¢ã«ãã¾ããã
Botå´ã®ããã°ã©ã ã¯ç¹ã«é£ãããã¨ããªãé 調ã«é²ã¿ã¾ããã
AIå´ã®ããã°ã©ã ä½æ
é¡ç»åãå¤æããã®ã«ãã£ã¼ãã©ã¼ãã³ã°ãå©ç¨ããã®ã§GPUãµã¼ãã¼ãå¿ è¦ã§ããã¯ã©ã¦ãã使ãã¨æ°ä¸å/æããã£ã¦ãã¾ãã®ã§èªåã®GPUãµã¼ãã¼ãå©ç¨ãã¾ããï¼ãã ã®ã²ã¼ãã³ã°PCã«é»æºãGPUã追å ããã ãã§ãããï¼ä¹ ãã¶ãã«PCã触ã£ããç»é¢ãä»ããªãã¦ç¦ãã¾ãããçµå±ã¯ãã¶ãã«é»æºãä¾çµ¦ããã±ã¼ãã«ãå£åãã¦ããã ãã ã£ãã®ã§ãããããã解決ããã®ã«1~2æ¥ãã£ã¦ããã¦ãªããªãè¾ãæãã§ãã...ð¦
AIå´ã®ããã°ã©ã ã¯ããªã¢ã«ãã¼ãã£ã«Youtuberãã§ä½ã£ãããã°ã©ã ãæµç¨ãã¦ãã¾ããAIã§é¡å¤æããé¨åã¨Webãµã¼ãã¹ãå¯çµåã«ãªã£ã¦ããã®ã§ãããã ãä¿®æ£ãã¦ç¬ç«ããå½¢ã§ä½¿ããããã«ãã¾ãããå¦ç¿ã¢ãã«ã¯ãã®ã¾ã¾æµç¨ã§ããæãã ã£ãã®ã§æµç¨ãã¦ãã¾ãã
GPUãµã¼ãã¼ã®ã»ããã¢ãã(ç©ç)ã«ããªãã¦ãããã¾ãããããªãã¨ããªãªã¼ã¹ã¾ã§ã«å®æã§ãã¾ããã
å®æãããããã¯ãã§ç¤¾å¡ããã®é¡ãå¤ãã¦éãã§ããããçµæ§åãã§ãããã¾ãããããã£ãããã£ãð
KPTã§ãµãããã
KPTã®åºæ¬
æå¾ã«ç ä¿®å ¨ä½ãKPTã§ãµããããã¾ãã
KPT(Keep/Problem/Try)ã¨ã¯ã·ã³ãã«ã§å¼·åãªãµããããã®ææ³ã§ãã
3ã¤ã®è¦ç´ ã«åãã¦ç¾ç¶åæãè¡ãã¾ãã
- Keep: è¯ãã£ããã¨ï¼ä»å¾ãç¶ãããã¨ï¼
- Problem: æªãã£ããã¨ï¼ä»å¾ã¯ããããã¨ï¼
- Try: 次ã«ææ¦ãããã¨ï¼Problemã®æ¹åçãKeepã§ããã«æ¹åãããã¨ï¼
ãµãããããåæ»ã«ããããããã«ã以ä¸ã®ã°ã©ã¦ã³ãã«ã¼ã«ãç¨æããã¦ãã¾ãã
- ç©æ¥µçã«è©±ããåå ãã
- å½äºè æèãæã¤
- 1人ã§è©±ããããªã
- çºè¨ããããããªã
- 話ãã¦ãªã人ã«ãæããã
- åå 追æ±ããããå人ã®è²¬ä»»è¿½æ±ãããªã
- 罪ãæãã§äººãæã¾ã
- ã人 vs 人ãã§ã¯ãªããããã¼ã vs åé¡ãã®æ§å³ãæèãã
- ã ããèªå·±å¼è·ãä¸è¦
åè: 振り返り/agile-looking-back - Speaker Deck
KPTã§ãµãããã
ã¾ãèªåã¨ã¡ã³ã¿ã¼ããã¨ç¤¾é·ã§ããããKeepã¨Problemãä»ç®ã«æ¸ãåºãã¦ããã®å¾Problemã«å¯¾ããTryãåºãåã£ã¦ããã¾ããã
ãããªæãã§ãã
- Keep
- ææ¥éããªãªã¼ã¹ã§ãã
- ç ä¿®ã§å¦ãã ãã¨ããããã¯ãéçºãéãã¦ä¸éãå®è·µã§ãã
- ã¹ã³ã¼ãåããã§ãã
- Problem -> Try
- GPUãµã¼ãã¼ã®ã»ããã¢ããã«è¦æ¦ãã¦æéå±ããã£ã -> å¿ é ã§ãªã¹ã¯ãé«ãã¹ãã¼ãªã¼ã¯å ã«è¦éãããã¦ã¦ãã
- ã³ã¼ãã¬ãã¥ã¼ã§ããªãã£ã -> 詳細è¨è¨ã¨ã話ãåã£ã¦ããã°ãã®æã«ã§ãã
- ç ä¿®ã§å¦ãã ãã¨ãããå¿ããã -> ç ä¿®ã§å¦ãã ãã¨ãããã°ã«ã¾ã¨ããã°æãåºã
ã¾ãææ¥éããªãªã¼ã¹ã§ããã®ãä½ããã§ããããã¨ã¯è¬ç¾©ã§å¦ãã ãã¨ãå®éã®ãããã¯ãéçºãéãã¦ä¸éãã§ããã®ã¯è¯ãçµé¨ã«ãªãã¾ãããããããã®ã¯å®éã«ãã£ã¦ã¿ãªãã¨ããããªããã¨ãå¤ããã身ã«ã¤ããªããã®ã ã¨æãã®ã§ãæ£ç´ããã ãã ã¨ã¾ã åºç¤ãæããã ããªã®ã§ä»å¾å®åã§çµé¨ãç©ãã§ãããªããã°ãªããªãã®ã§ãããããªã¼ã©ã³ã¹ã®ç ä¿®ã¨ãã¦ã¯ååãããã»ã©æéã使ããã¦ãããã¦è¯ãçµé¨ãç©ããã¨ãã§ãã¾ããã
ãããã«
ã¡ã³ã¿ã¼ã¨ãã¦éçºã«ä»ãåã£ã¦ãã ãã£ã @sssgggiiiããã@harada4atsushi ããããäºäººã®ãããã§ãªãã¨ãå®æããããã¨ãã§ãã¾ãããæ¬å½ã«ãããã¨ãããã¾ããð
èªåã®ä¸ã§ã¯ãã®è¨äºã®å ¬éããããã¯ãã®æ£å¼ãªãªã¼ã¹ã®ã¤ãããªã®ã§ããããªãã¨ãå½¢ã«ãªã£ã¦ã»ã£ã¨ããæ°æã¡ã§ãã
ãªã¼ã³éçºã¨ãã¦ã¯Build -> Measure -> Learnã«ã¼ãã®æåã®Buildãçµãã£ãã ãã§ããããããæ¬çªãªæãã§ããä»å¾ã¯å®éã«ä½¿ã£ã¦ããã£ã¦ãã£ã¼ãããã¯ã«ã¼ããåãã¦ãããããªã¼ã¨æãã¾ããï¼ãã ããã§ã«ããæ°ãæ¶ãããã¦ã¾ã ãå人éçºã§ä¸åº¦ãªãªã¼ã¹ããã¨ããæ°ãæ¶ããåé¡ãããå æ¸ã©ãã«ããããã§ãã»ã»ã»ðï¼
ããããRailsã¨ã³ã¸ãã¢ã®ã¸ã¬ã³ã
ããã«ã¡ã¯ãããããRailsã¨ã³ã¸ãã¢æç¥ä»£è¡¨ã®shitaã§ãã
æè¿ãã£ã¨ã«ããããmofmofããã®ãã¼ãã¢ããã§ãé§ãåºãã¨ã³ã¸ãã¢ã®æ¹éã«å°±è·ã®ç¸è«ãããã ããã¨ãããã¾ããã
èªåã¯æªã ã«ãããããªã®ã§ãããé§ãåºãã¨ã³ã¸ãã¢ã®é ã¯ä»ãããã£ã¨ããããã§ããããã®æã«Railsåéã¨è©±ãã¦ããæ©ã¿ãæãåºããã®ã§ããã§å ±æããã¦ãã ããã
ããããRailsã¨ã³ã¸ãã¢ã®ã¸ã¬ã³ã
ããããRailsã¨ã³ã¸ãã¢ã¯ãããããªç¾å ´ã«ããå ¥ããæè¡åãä¸ãããªãã®ã§ããã£ã¨ãããããªç¾å ´ããè±åºã§ããªãã
- ã¤ãã¤ããªç¾å ´ã¯ã¤ãã¤ãRailsã¨ã³ã¸ãã¢ãæ±ãããããããããRailsã¨ã³ã¸ãã¢ã¯ãããããªç¾å ´ã«å ¥ããããªã
- ããããããããªç¾å ´ã§ã¯æè¡åãä¸ããã®ãé£ãã
- æè¡åãä¸ãããªãã®ã§ãããããã¨ã³ã¸ãã¢ã¯ã¤ãã¤ããªç¾å ´ã«å ¥ããã¨ãã§ããããã£ã¨ãããããªç¾å ´ããè±åºã§ããªã
ããã¦ãããããªç¾å ´ã¯ãè³éãä½ããã©ãã¯ãªãã¨ãå¤ããããå¾ã ã«ç²¾ç¥çã«è¿½ãè¾¼ã¾ãã¦ããã¾ãã
ããããããªç¾å ´ã§ã¯æè¡åãä¸ããã®ãé£ãããã¨ããã®ããã¤ã³ãã§ãã
(ããã§è¨ãã¤ãã¤ããªç¾å ´ã¯ãããããããµã¤ãã®ãRailsã¢ããªã±ã¼ã·ã§ã³éçº ããã£ã¦ããç¾å ´ãæãã¾ããRailséçºã§å½ããåã¨ããã¦ãããã¨ãã§ãã¦ããç¾å ´ã§ãããã¹ããæ¸ããã¦ãããã©ããã1ã¤åããç®ãã¨æãã¾ããã¾ã¨ããªãã¹ããæ¸ãã«ã¯ã¾ã¨ããªè¨è¨ãå¿ è¦ãªã®ã§ããããããªç¾å ´ã¯ãã¹ããæ¸ãã¾ããã)
ãããããªç¾å ´ã§ã¯æè¡åãä¸ããã®ãé£ãã
ãããããªç¾å ´ã§ãæè¡åãä¸ãããã¨ã¯ä¸å¯è½ã§ã¯ãªãã§ãããå®éã«ã¯ãªããªãé£ããã®ãç¾å®ã§ããçç±ã¯ä»¥ä¸ã®ã¨ããã§ãã
ã¤ãã¤ããªã³ã¼ãã«è§¦ããããªã
ã¤ãã¤ããªç¾å ´ã«ã¯ã¤ãã¤ããªã³ã¼ããããã¾ããã¡ããã¨DBè¨è¨/ã¯ã©ã¹è¨è¨/URLè¨è¨çãè¡ããã¦ãã¦ãRuby/Railsã®æµåã«åã£ã¦ãã¦ãFatã³ã³ããã¼ã©ã¼/Fatã¢ãã«ã§ã¯ãªããã¡ã³ãããã«ã§ãªã¼ããã«ãªã³ã¼ããããã¾ããæ¯æ¥ã¤ãã¤ããªã³ã¼ãã«è§¦ããã®ã¯ãæ¯æ¥Railsã®ãã¹ããã©ã¯ãã£ã¹ãå¦ãã§ãããããªãã®ã§ãããã ã³ã¼ãã«è§¦ãã¦ããã ãã§ãèªç¶ã¨è¯ãæ¸ãæ¹ã身ã«ã¤ãã¦ããã¾ãã
ä¸æ¹ãããããªç¾å ´ã«ã¯ãããããªã³ã¼ããããã¾ãããã¹ãã³ã¼ãã¯ãªããRestfulã§ã¯ãªãããã¡ã¤ã³ãã¸ãã¯ã¯ã¢ãã«ã«æ¸ããããã³ã³ããã¼ã©ã¼ã¯1000è¡ãè¶ ãã¾ããé§ãåºãã¨ã³ã¸ãã¢ã®å ´åã¯çµé¨ãæµ ãã®ã§ãRailsã¯ãããªæããªã®ãã¨æã£ã¦ãã¾ãã¾ããæ¯æ¥ãããããªã³ã¼ãã«è§¦ããã®ã¯ãæ¯æ¥Railsã®ããããã©ã¯ãã£ã¹ãæ£ããæ¸ãæ¹ã¨ãã¦å¦ãã§ãããããªãã®ã§ãããã ã³ã¼ãã«è§¦ãã¦ããã ãã§ãèªç¶ã¨æªãæ¸ãæ¹ã身ã«ã¤ãã¦ããã¾ãã
ã³ã¼ãã¬ãã¥ã¼ãåããããªã
ã¤ãã¤ããªç¾å ´ã§ã¯ã³ã¼ãã¬ãã¥ã¼ãåãããã¾ããã³ã¼ãã¬ãã¥ã¼ã¯ã¹ãã«ã¢ããã®å ´ã§ãããã¾ããè¯ããªãã³ã¼ããæ¸ãã¦ãã¾ã£ãå ´åã§ãã³ã¼ãã¬ãã¥ã¼ã§ææãã¦ããããã®ã§ãã³ã¼ãã¬ãã¥ã¼ã®ãã³ã«æ°ããå¦ã³ãå¾ããã¾ãã
ä¸æ¹ãããããªç¾å ´ã«ã¯ã³ã¼ãã¬ãã¥ã¼ã¯ããã¾ãããè¯ããªãã³ã¼ããæ¸ãã¦ãããããè¯ããªãã³ã¼ãã ã¨æ°ã¥ããã¨ã¯ããã¾ããã
ã¢ãã³ãªæè¡ã«è§¦ããããªã
ã¤ãã¤ããªç¾å ´ã¯ã¢ãã³ãªæè¡ãæ¡ç¨ãã¦ãã¾ããã¤ãã¤ããªç¾å ´ã«ã¯æè¡å¥½ããªäººéãéã¾ããããæ°ããæè¡ã«ã¤ãã¦ã®ç¥è¦ãå ±æãããããã¸ã§ã¯ãã«ããããããããªãèªç¶ã¨æ¡ç¨ããã¦ããã¾ãã
ä¸æ¹ãããããªç¾å ´ã¯ã¬ã¬ã·ã¼ãªæè¡ã使ããç¶ãã¾ããé¸æã®çµæããã¦ã¬ã¬ã·ã¼ãªæè¡ãæ¡ç¨ããã®ãªãè¯ãã®ã§ããããããããªç¾å ´ã¯ããããã¢ãã³ãªæè¡ãç¥ããªããé¢å¿ãããã¾ãããCoffeeScriptã¨jQueryã使ãç¶ãã¾ãããã®çµæãã¤ãã¤ããªç¾å ´ã§æ±ããããã¹ãã«ã»ããã¨èªåã®ã¹ãã«ã»ããã®éã§ãºã¬ãçãã¦ãã¦ã¾ãã
åå¼·æéã確ä¿ã§ããªã
ã¤ãã¤ããªç¾å ´ã¯ãã¯ã¤ãã§ããã¤ãã¤ããªç¾å ´ã¯ã¤ãã¤ããªRailsã¨ã³ã¸ãã¢ãæ¡ç¨ããããã«åããããç°å¢ã¥ããã«åãå ¥ãã¦ãã¾ããä»ã¾ã§ãä¸è©±ã«ãªã£ãã¤ãã¤ããªç¾å ´ã§ã¯å½ããåã®ããã«æ®æ¥ã¯ããã¾ããã§ãããä»äºã¯æ©ã ã«çµããã®ã§ãæ¥åå¾ã«èªå·±ç é½ã«æéã使ãã¾ããã¨ããããã¤ãã¤ããªç¾å ´ã§ã¯æ¥åæéä¸ã«ãåå¼·ã§ãã¾ããæãä¸è©±ã«ãªã£ãä¼ç¤¾ã§ã¯æ¥åæéä¸ã«æ®éã«åå¼·ä¼ãéããã¦ã¦ãç®ãçé£ã³åºããããã³ã£ããããã®ãè¦ãã¦ãã¾ããå½æã®èªåã¯åå¼·ã¯æ¥åæéå¤ã«ãããã®ã ã¨æã£ã¦ããã®ã§ãããã©ããã¤ãã¤ããªç¾å ´ã§ã¯ãããã¾ãã®ãã¨ã®ããã§ãã
ä¸æ¹ãããããªç¾å ´ã¯ãã©ãã¯ã§ããå½ããåã®ããã«æ®æ¥ããããããæ°ããæè¡ã®åå¼·ã«ã¯ãªããªãæéãå²ãã¾ãããçµæãæ´æ°ãããªãã¾ã¾ã®ææã¡ã®ç¥èã§ãªãã¨ããããã¨ããããç¡çã®ããè¨è¨/å®è£ ã«ãªã£ã¦ããã¾ããã¡ã³ããã³ã¹æ§ã¯èæ ®ããããã³ã¼ãã¯ããã«å°çã¨åãã¦ãããããã¸ã§ã¯ãã¯çä¸ããããã«åå¼·æéã確ä¿ããã®ãé£ãããªã£ã¦ããã¾ãããã¨ãã¡ããããæ·±å»ãªã®ã§ããããã©ãã¯ãªã®ã§ç²¾ç¥çã«æ©èãã¦ãã¾ãã家ã«å¸°ã£ã¦ãåå¼·ããæ°åãæ®ã£ã¦ãã¾ããã
ãããããªç¾å ´ãè±åºããã«ã¯ï¼
ãããããªç¾å ´ãè±åºããã«ã¯ã¤ãã¤ããªç¾å ´ã§çµé¨ãç©ãã®ãä¸çªã§ãããã§ã«è¿°ã¹ãã¨ããæ®éã«ã¯ã¤ãã¤ããªç¾å ´ã«ã¯å ¥ãã¾ãããããããªæãã§ä¸å·¥å¤«ããã°å¯è½æ§ãåºã¦ããã®ããªã¼ã¨æãã¾ãã
ã¤ãã¤ããªç¾å ´ã«ã¢ã«ãã¤ãã§å ¥ã
ããã¯èªåãã¨ã£ãæ¹æ³ã§ãã
ä¼ç¤¾ã¨ãã¦ã¯æ£ç¤¾å¡ãæ¡ç¨ããããã¢ã«ãã¤ããæ¡ç¨ããã»ããæ·å± ãä½ãã§ãããã®ãããã¨ããããã¢ã«ãã¤ãã¨ãã¦ã¤ãã¤ããªç¾å ´ã«å ¥ã£ã¦çµé¨ãç©ãã®ã¯ããã ã¨æãã¾ããéçºçµé¨ã¨ãã¦ã¯æ£ç¤¾å¡ã¨éè²ã®ãªãçµé¨ãç©ãã¾ããããã®ã¾ã¾æ£ç¤¾å¡ã«èªããããã¨ãããã¾ãã
ãã£ã¨ã«ããã¼ããã£ã³ãã«åå ãã
ãããèªåãã¨ã£ãæ¹æ³ã§ãã
ãã£ã¨ã«ããã¼ããã£ã³ãã¯ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã§ãããã ãä»ã®ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã¨ã¯ã ãã¶éã£ã¦ãã¦ãåç´ãªRailsã®ç¥èãæããã®ã§ã¯ãªãå®éã«ã¤ãã¤ããªç¾å ´ã§åããã ãã®ç¾å ´åã身ã«ã¤ãã¦ããããã¨ã«ãã©ã¼ã«ã¹ãã¦ãã¾ãã
æè¨äºãæ¸ããã®ã§ã詳ããã¯ãã¡ããã©ããã
ã¡ã³ã¿ã¼ã®@komagataãã@machidaããéã¨ä¸ç·ã«OSSã®Railsã¢ããªã±ã¼ã·ã§ã³ãéçºãããã®ã§ãããããã¯ã¤ãã¤ããªç¾å ´ãã®ãã®ã§ãããã£ã¤ãã¤ãã¤ããªç¾å ´ã®çµé¨ãç©ãã¾ãã
é§ãåºãã¨ã³ã¸ãã¢ãåéãã¦ããã¤ãã¤ããªä¼ç¤¾ãæ¢ã
ã¤ãã¤ããªä¼ç¤¾ã¯ãæ°åãé¤ãã¦ããã¾ãæªçµé¨è ãåéãã¦ãã¾ããã
ããããã¤ãã¤ããªä¼ç¤¾ã§ãé§ãåºãã¨ã³ã¸ãã¢ãç©æ¥µçã«åéãã¦ããå ´åãããã¾ããããããä¼ç¤¾ã¯ç ä¿®ããã£ãããã¦ãã¦ãã¾ã ã¾ã ãããããªé§ãåºãã¨ã³ã¸ãã¢ãåãå ¥ããä½å¶ãã§ãã¦ããã®ããªã¼ã¨æ³åãã¾ãã
ä¾ãã°èªåãããªã¼ã©ã³ã¹ã¨ãã¦ãä¸è©±ã«ãªã£ã¦ããmofmofããã¯ãå®åæªçµé¨/å®åçµé¨ãæµ ãRailsã¨ã³ã¸ãã¢ã®æ¹éã«åãã¦å®æçã«ãã¼ãã¢ãããéãã¦ãã¾ãã
ãã®ä¼ç¤¾ãã¤ãã¤ããã©ããã¯ãå®éã«ç¾å ´ã§åãã¦ããã¨ã³ã¸ãã¢ããéã«èãã®ãè¯ãã¨æãã¾ããç¥ãåãã®ã¨ã³ã¸ãã¢ã«èãããåå¼·ä¼ã®æ親ä¼ãªã©ã§èãã°æãã¦ããããããªã¼ã¨æãã¾ãã
ä»ã®æ¹æ³
ãã¨ã¯OSSæ´»åãè¯ãã¨æãã®ã§ãããOSSæ´»åã§ããæç¹ã§æ¢ã«ããããã§ã¯ãªãããªã¼ã¨ã
åå¼·ä¼ã«è¡ãã®ã¯ã¤ãã¤ããªç¾å ´ã®ã¤ãã¤ããªç¥è¦ãå¾ããã¦è¯ãã¨æãã¾ãããã ãããããªç¾å ´ã ã¨åºæ¬çä¸ãã¦ããã®ã§ããã®æéã¨ä½åãæ»åºããã®ããã£ããé£ããã£ãããã¾ãã
ã¾ã¨ã
æè¿ã¯ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ãå¢ãã¦é§ãåºãã¨ã³ã¸ãã¢ã大éã«å¢ããããããã¤ã®å¥ªãåããæ¿ãããªã£ã¦ãé§ãåºãã¨ã³ã¸ãã¢ã®å°±æ´»ãããå³ãããªã£ãã¨èãã¾ãããã®ããä»æ¹ãªããããããªç¾å ´ã«å ¥ãæ¹éãå¢ãã¦ããã®æ¹éããã®ã¸ã¬ã³ãããæãåºããªããªã£ã¦ãã¾ãã®ã§ã¯ãªããã¨å¿é ã§ãã
åªç§ãªäººã§ããã°ãããããªç¾å ´ã«è¡ã£ãã¨ãã¦ãåæã«æé·ãã¾ããããããç¾å ´ãæ¹åãã¦ããããã ããã¨æãã¾ããããããèªåãå«ãã¦å¤ãã®é§ãåºãã¨ã³ã¸ãã¢ã¯ã¾ã ã¾ã ããããã§ããããã¯ã¨ã¦ãé£ãããã¨ã§ãã
é§ãåºãã«ã¨ã³ã¸ãã¢ã¨ã£ã¦ãããããªç¾å ´ãé¿ãããã¨ã¯ã¨ã¦ã大åãªãã¨ã ã¨æãã¾ãããããããªç¾å ´ã«å ¥ã£ã¦ãã¾ããå¿ããããã¦ãã¾ã£ãã¨ãã話ãããã¤ãèãããã¨ãããã¾ãããã£ããåå¼·ãã¦ããçµæãããã§ã¯æ²ãããã¾ãã
é§ãåºãã¨ã³ã¸ãã¢ã®ã¿ãªããã®å°±è·ãä¸æããããã¨ãå¿ããé¡ãã¾ãð
Sendagaya.rbããã«ååå ããã¦ããã ãã¾ããï¼
å æ¥ãä»äºã®ããã«æ±äº¬ã«å¼ã£è¶ããã®ã§ãããæªã ã«ããããå±ããåºã«å¯ã¦ãã¾ããå¼ã£è¶ãä½æ¥å¤§å¤ããã¦ãä»äºéå§ã¾ã§ã«çµãããå¿é ã«ãªã£ã¦ãã¾ããã»ã»ã»ã
æ¨æ¥Sendagaya.rb #295ã«åå ããã¦ããã ãã¾ããï¼
ãã£ã¨ç°èã«å¼ãããã£ã¦ãã¦åå¼·ä¼ã«åå ããã¦ããã ãã®ã¯ä¹ ãã¶ãã ã£ãã®ã§ç·å¼µãã¾ããã¼ã
æµãã¨ãã¦ã¯ãããªæãã§ããã
- @s4naããã®æè¡çãªç¸è«ãã¿ããªã§èãã
- èªå·±ç´¹ä»
- 軽ãæ親ä¼(ã®ã¯ãã§ããããåºãã®ãªã®ãªéã¾ã£ã¦ãã¾ã£ã)
@s4naããã®æè¡çãªç¸è«ãã¿ããªã§èãã
Rubyã«ã¯WebMockã¨ããHTTPãªã¯ã¨ã¹ããã¢ãã¯ããgemãããã®ã§ãããããããã¾ãæ©è½ããªãã¨ããç¸è«ã§ãããã¢ãã¯ãã¦ããã¯ããªã®ã«ãªã¯ã¨ã¹ããé£ãã§ãã¾ãã
æ示ãããã³ã¼ãã¯ãããªæãã§ããã¼
WebMock.enable! WebMock.stub_request(:get, url).to_return(response)
ããããªæè¦ãåºãã¾ãããã以ä¸è¦ãã¦ããé¨åã ãç®æ¡æ¸ãã§ã¼ã
- ã¢ãã¯ããã³ã¼ãã®ç´å¾ã«ãã¬ã¼ã¯ãã¤ã³ãä»æãã¦è©¦è¡é¯èª¤ãã¦ã¿ãã¨è¯ããã
- VS Codeã§ãã¬ã¼ã¯ãã¤ã³ãä»æããã«ã¯ã©ãããã°ï¼ -> ããã使ãã¨è¯ããã Visual Studio Codeを使ってRailsをデバッグ実行してみよう - Qiita
- ãã¨binding.pryã使ãã®ãããã -> pry-byebug
- HTTPã¡ã½ãããURLãããããã¦ããªãå¯è½æ§ããããã
- åé¡ãåãåããããã«ã
:any
ã*
ã使ã£ã¦ãããããªã¯ã¨ã¹ããã¢ãã¯ã§ããã®ã調ã¹ã¦ã¿ãã -> ã¢ãã¯ã§ããªãã£ããã¢ãã¯ããã³ã¼ãã§ã¯ãªããä»ã®é¨åã«åé¡ããããã
- åé¡ãåãåããããã«ã
- ç¹å®ã®æ¡ä»¶ã§ã¢ãã¯ãdisabledã«ãªã£ã¦ãã¾ãå¯è½æ§ããããã
- ä»åã¯å¤é¨APIã¸ã®ãªã¯ã¨ã¹ãã§ã¯ãªããlocalhostã¸ã®ãªã¯ã¨ã¹ãã ã£ãããã®å ´åã¯ããããããããã©ã«ãã§disabledã«ãªã£ã¦ãã¾ãï¼ -> 調ã¹ã¦ã¿ãã¨ãããããã¨ã§ã¯ãªãã£ã
- ãã®è¾ºããæªãã https://github.com/bblimke/webmock#external-requests-can-be-disabled-while-allowing-specific-requests -> 調ã¹ã¦ã¿ãã¨ãããããã¨ã§ã¯ãªãã£ã
- ä½ãè¦è½ã¨ãããããããããããè«ã¨ãã¦å¦çã®ããã¼ã¯ã©ããªæãï¼
- æ¤ç´¢ãã¿ã³ãæ¼ã -> ãã©ã¦ã¶ãããµã¼ãã¼ã«/tweets.json(ã¯ã¨ãªãã©ã¡ã¼ã¿) -> ãµã¼ãã¼ãtwitter gemã使ã£ã¦ããã¤ã¼ããåå¾ -> ãµã¼ãã¼ãJSONã§ãã©ã¦ã¶ã«æ å ±ãè¿ã
- ãã¹ãã³ã¼ãã§ã¯Capybaraã®
visit
ã¡ã½ããã使ã£ã¦APIã«ã¢ã¯ã»ã¹ãã¦ããããããã¢ãã¯ãããã -> ããï¼visit
ã£ã¦ã¢ãã¯ã§ãããã ã£ãï¼
- Webmockã¯ã©ã®é¨åãã¢ãã¯ããï¼
ã¨ãããã¨ã§ãWeb APIã«visit
ã§ãã©ã¦ã¶ã¢ã¯ã»ã¹ãã¦ããã®ã§ã¢ãã¯ã§ããªãã¨ãããã¨ã§ããã¼ã
ãã®å¾ãããããæ´¾çãã¦è²ã ãªå¦ã³ãããã¾ããã
- ãã©ã¦ã¶ã¢ã¯ã»ã¹ãWebmockã§ã¢ãã¯ã§ããgemãããã -> puffing-billy
- ãªã¯ã¨ã¹ãæ å ±ããã³ãããgemããããããã£ã¡ã便å©ãã -> http-dump
- ã³ã³ããã¼ã©ã¼ã«TwitterAPIã¸ã®ã¢ã¯ã»ã¹å¦çããã¿æ¸ããã¦ãã¾ã£ã¦ãããããã ã¨Fatã³ã³ããã¼ã©ã¼ãªã®ã§ãTwitterã¸ã®ã¢ã¯ã»ã¹é¨åã ãPOROã«åãåºãã¨è¯ããã
- å¤é¨APIã¸ã®ã¢ã¯ã»ã¹ã¯çµæ§å¤æ´ããã£ããããã®ã§ãåãåºãã¦ããã¨ä¿®æ£ãããããªã
- ã¢ãã¯ãç°¡åã«ãªãããªã¯ã¨ã¹ããã¢ãã¯ããã¨ããããããªã¯ã¨ã¹ãã®å¦çãã¤ã³ã¹ã¿ã³ã¹ã¡ã½ããã«éãè¾¼ãã¦ãããã丸ãã¨ã¢ãã¯ããã®ãè¯ããã
- ãã®å ´åãPOROã¯modelsé ä¸ã«ç½®ããlibã«ç½®ãããgemã«ããããã人ããã(ãã©ã¡ãã£ã¨ããéããã)
- ä¸è¨ã®ã¤ã³ã¹ã¿ã³ã¹ã¡ã½ããã¯ãã©ããã£ã¦åä½ãã¹ããããã°ããï¼
- å¤é¨APIããã¹ããããã¨ã«ãªã£ã¦ãã¾ãã®ã§ããã¹ãã¯çµæ§é£ãã
- æ¯åãªã¯ã¨ã¹ãããã®ã¯ã¾ããããVCRã使ã£ã¦ãã£ãã·ã¥ãã¦ããã¨å®è³ªçã«ã¯ãã¹ãã«ãªããªã
- ãªã¯ã¨ã¹ãã®å½¢å¼ã¯ãã¹ãã§ããããã¡ããã¨ããå¼æ°ã渡ã£ã¦ãããç¨åº¦ã®ãã¹ãã§ããããªã¼
- ãã¨ãã¹ãã¨ã¯å¥ã§å¤é¨APIã®åä½ããã§ãã¯ããCIãç¨æãããã£ã¦ããã®ã¯å¯è½ãä¾ãã°å¤é¨ãµã¤ãã®ç»é¢ãã¹ã¯ã¬ã¤ãã³ã°ãã¦æ å ±ãã¨ã£ã¦ãããããªå ´åã¯ãç»é¢ã¯å¤ãããããã®ã§ãã§ãã¯ã¯å¿ é ã«ãªãããã
ææ³
WebMockã§ã¢ãã¯ã§ããªã件ã¯ããããã¦èãã¦ã¿ãã¨ç°¡åãªãã¨ãªã®ã§ãããèªåã§PCãæä½ã§ããªãçã®å¶ç´ãããä¸ã§è§£æ±ºã«ã¾ã§è³ãã®ã¯ãªããªã大å¤ã§ãããèªåã¯è¦å½éããªãã¨ãè¨ã£ãããããããåé¡ãæ£ããç解ã§ãã¦ããªãã£ãããçµæ§è¿·æããã¦ãã¾ãã¾ãããã§ãçããã¯1ã¤ãã¤åé¡ãåãåãããããããããã¬ã¼ã å¤ã®æã«åé¡ãããã®ã§ã¯ï¼ã¨æ°ã¥ããããã¦ãã¦ãããããªã¼ã¨æå¿ãã£ã±ãªãã§ãããã©ãããæµãã§è§£æ±ºã¾ã§è³ããã@tkawaããã@fukajunããã@sanfrecce_osakaããéãå¼·ã人éã®æèã®éç¨ãçã§è¦ããã®ã¯ãã¡ãåå¼·ã«ãªãã¾ããï¼
ãã¨ä»åã¯ä¸»å¬è ã®@tkawaããã¨@fukajunãã以å¤ãåå è ã®4äººå ¨å¡ãã£ã¨ã«ããã¼ããã£ã³ãçï¼åæ¥çå«ãï¼ã¨ããå¥è·¡ãèµ·ãã¾ããâ¨èªåã¯ãã«ãªã¢ã¼ãã§ãã£ã¨ã«ããã¼ããã£ã³ããåæ¥ãã¦ãä»ã®çå¾ããã¨ä¼ãã®ã¯åãã¦ã ã£ãã®ã§ããªããªãç·å¼µãã¾ãããã§ã3人ã¨ãåªããæ¹ã ã£ãã®ã§å®å¿ãã¾ãããããã£ãã¼ãç¹ã«@NMPããã¨ã¯ãäºãä¸äº¬ããã°ããã§ãååå¼·ä¼åå ã¨ãããã¨ã§ææ°æåãã¾ããã
ããã¦ä¸»å¬è ã®@tkawaããã¨@fukajunããããµããã¨ãã¨ã¦ãåªããæ¹ã§ãæ¬å½ãªã¹ãã¯ãã§ãããRubyã³ãã¥ããã£ã®æ¹ãã¡ã¯ãçããæ¬å½ã«åªããã§ããããæåã§ãâ¨
ãã¨ä¼å ´ã®ã©ã³ãã§ã¹ã¿ã¼ãããåããããã§ããã
ä¹ ãã¶ãã®åå¼·ä¼ã§ç·å¼µãã¾ãããã楽ãããåå¼·ã«ãªããæé«ã®åå¼·ä¼ã§ããï¼ä¸»å¬è ã®çãããåå è ã®çãããä¼å ´æä¾ãã¦ãã ãã£ãã©ã³ãã§ã¹ã¿ã¼ããããããã¨ããããã¾ããã¼ï¼ ã
ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã®çæ³ã¨ç¾å®ããã¨ãã£ã¨ã«ããã¼ããã£ã³ãã«ã¤ãã¦
ï¼Railsã®ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã«ã¤ãã¦ã®è©±ã§ãããã¨èªåã¯ãã£ã¨ã«ããã¼ããã£ã³ãã®åæ¥çã§ããã¤ã¢ã¹ããã£ã¦ããããªã®ã§å·®ãå¼ãã¦ãèªã¿ãã ãããï¼
ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã«ã¤ãã¦ãã¾ããã話ãèãã¾ããã
çä¸ç³»ã®ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã ãã§ãªãããã®ä»ã®ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã«ã¤ãã¦ããã¬ãã£ããªè©±ãçµæ§èãã¾ãã
æ£ç´èªåãããã°ã©ãã³ã°ã¹ã¯ã¼ã«æ¥çã«ã¯è¯ãã¤ã¡ã¼ã¸ã¯ãªãã®ã§ãããã¨ã¯ããã¡ããã¨æ¢ãã°è¯ãããã°ã©ãã³ã°ã¹ã¯ã¼ã«ãï¼å°ãã ãï¼åå¨ãã¾ãããã®è¨äºã¯ãããªã話ã§ãã
ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã®çæ³ã¨ç¾å®
ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã®åé¡ç¹ã¯æ確ã§ãããã°ã©ãã³ã°ã¹ã¯ã¼ã«ãåæ¥ãã¦ãç¾å ´ã§åããã ãã®å®åãã¤ããªãã¨ãããã¨ã§ãã
ãããªã¤ã¡ã¼ã¸ã§ãã
ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã§ã¯Railså¨ãã®åºç¤ãä¸éãåå¼·ãã¦ãWebãµã¼ãã¹ãå人éçºãã¦åæ¥ã®ã¨ãããå¤ãããªã¼ã¨æãã¾ããã§ãããã ã¨ç¾å ´ã§åããã¬ãã«ã¾ã§å±ããªãã§ããå³ã®ç¾å ´å
ã«ç¸å½ããè½åãä¸è¶³ãã¦ãã¾ããå
·ä½çã«ã¯
- ãªãã¸ã§ã¯ãæåã«ããã¯ã©ã¹è¨è¨å
- DBè¨è¨å
- URLè¨è¨å
- èªã¿ãããã³ã¼ããæ¸ãå
- ã¢ã¸ã£ã¤ã«/ã¹ã¯ã©ã å
- æªç¥ã®åé¡ãèªåã§èª¿æ»ãã¦è§£æ±ºããå
- ãªã©ãªã©
ãããã®è½åã身ã«ã¤ããã«ã¯æè¡æ¸ãèªãã ãã ã¨è¶³ãã¾ãããå®éã«åªç§ãªRailsããã°ã©ãã¨ä¸ç·ã«éçºããããã³ã¼ããã¬ãã¥ã¼ãã¦ããã£ããããã¢ãããããããªãããå®è·µã¨ãã£ã¼ãããã¯ãç¹°ãè¿ããã¨ã§æ¥ã å°ããã¤æé·ãã¦ããã¾ãã
ãã£ã¨ã«ããã¼ããã£ã³ãã®ã¡ã³ã¿ã¼ã® @komagata ãããã詳ããæ¸ãã¦ããã®ã§ãã¡ãããããã§ãã¼ã -> Railsエンジニアとして就職できるレベルとは - komagataのブログ
ç¾å ´ã§åããã ãã®å®åãã¤ããªãã®ã§ãå°±è·ããªããªãé£ããã§ãããã£ã¨ã«ã以å¤ã®ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã®æ¹ã¨ã話ããã¦ãããæ©ä¼ãããã¾ããããã¿ãªããå°±è·ã«è¦æ¦ããã¦ãããã§ããã
ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã¯è¯ãã¡ã³ã¿ã¼ãéããªãåé¡
ç¾å ´åãéããããã«ã¯ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã¯åªç§ãªã¡ã³ã¿ã¼ãéãå¿ è¦ãããã®ã§ãããããã¯ã¨ã¦ãé£ããã§ããåªç§ãªã¡ã³ã¿ã¼ã¯åªç§ãªããã°ã©ããªã®ã§ãé«ããããå¼ãæãã¾ããªã®ã§ããåªç§ãªã¡ã³ã¿ã¼ãéããªãã®ã§ãããã°ã©ãã³ã°ã¹ã¯ã¼ã«ãåæ¥ããã°ããã®ç¾å ´æªçµé¨ã®æ¹ãã¡ã³ã¿ã¼ã¨ãã¦éããããªäºæ ãèµ·ãã¦ãã¾ãã¾ããï¼ãã®ã¬ãã«ã§ãåºç¤ã§ããã°æããããã®ã§å¿ ãããæªããã¨ã§ã¯ãªãã¨æãã¾ãããã ãç¾å ´ã¬ãã«ã®ãã£ã¼ãããã¯ã¯å¾ããã¾ããããç¾å ´åãéããã«ã¯ãããã¨ã¦ã大åã§ããï¼
ãã£ã¨ã«ããã¼ããã£ã³ããªããç¾å ´åã身ã«ä»ããããã
ãã£ã¨ã«ããã¼ããã£ã³ãã¯ä¸è¨ã®åé¡ã解決ãã¦ãã¾ãã
å®éã«ç¾å½¹ã®ã¨ã³ã¸ãã¢/ãã¶ã¤ãã¼ã§ãã @komagata ãã㨠@machida ããã®äºäººãç´æ¥ã¡ã³ã¿ã¼ã«ãªã£ã¦ããã¾ããRubyã³ãã¥ããã£ã§æåãªäºäººãªã®ã§ç¥ã£ã¦ããæ¹ãå¤ãã¨æãã¾ãããäºäººã¯ä»ã®ä»äºãããªããããã£ã¨ã«ãã®ä¼ç¤¾çµå¶ãããªãããã¡ã³ã¿ã¼ããã¦ããã¾ããã©ãæéãä½ã£ã¦ããã®ï¼ã¹ã¼ãã¼ãã³ã§ãã
ãã£ã¨ã«ããã¼ããã£ã³ãã§ã¯Bootcampã¨ããå¦ç¿ç¶æ³ãæ¥å ±ã管çããç¬èªã®Rails製ãµã¼ãã¹ãå©ç¨ãã¦ãã¾ããåºç¤ã®å¦ç¿ãä¸éãçµããã¨ããã®ãµã¼ãã¹ãäºäººã¨ä¸ç·ã«éçºãã¦ãããã¨ã«ãªãã¾ããå®éã«ä»ã¾ã§èªåã使ã£ã¦ãããµã¼ãã¹ãéçºããå½¢ã«ãªãã®ã§ãã¹ã ã¼ãºã«éçºã«å ¥ãã¾ãããã®éçºã®ä¸ã§ã¹ã¯ã©ã ãçµãã ãããã¢ããããããGithubä¸ã§ã¬ãã¥ã¼ãã¦ããã£ãããããã¨ã§ãç¾å ´åãéãã¦è¡ããã¨ãåºæ¥ã¾ãã
ã¬ãã¥ã¼ãã¦ããããã®ã¯ã³ã¼ãã ãã§ã¯ãªãã§ããWebãµã¼ãã¹ã®å人éçºã®ãã©ã¯ãã£ã¹ã§ã¯ãã¨ã¬ãã¼ã¿ã¼ãããããã¼ãã¼ãããã¿ã¤ããWebãµã¼ãã¹ã®ãã¶ã¤ã³ãªãããã¬ãã¥ã¼ãã¦è²°ãã¾ãããã¡ãã¯ãã¶ã¤ãã¼ã® @machida ããã主ã«ã¬ãã¥ã¼ãã¦ããã¾ãããã®è¨äºãèªãã§ããããã°ã©ããªæãã§ã¬ãã¥ã¼ãã¦ããããããé°å²æ°ããããã¨æãã¾ãã -> プログラミングスクールで、「リアルバーチャルYoutuber」というWebサービスを作りました - 猫Rails
ãã¨ãä¾ãã°ãã£ã¨ã«ããã¼ããã£ã³ãã«ã¯ãlsã³ãã³ããRubyã§ä½ã£ã¦ãã ãããã¨ãã課é¡ãããã¾ããããã¯ãã åãã ãã§ã¯é§ç®ã§ãRubyã®ã³ã¼ãã¨ãã¦ãªã¼ããã«ã§ã¡ã³ããã³ã¹ããããã³ã¼ããæ¸ãå¿ è¦ãããã¾ãããã®åé¡ã«çãã¯ããã¾ãããããã§çå¾ããéã¯ãåèå³æ¸ã®ãªãã¸ã§ã¯ãæåè¨è¨å®è·µã¬ã¤ããèªãã ãã@komagataããã«ä½åº¦ãã¬ãã¥ã¼ãã¦ããã£ãããï¼èª²é¡ã¯ãªã¢å¾ã«ï¼ä»ã®çå¾ããã®ã³ã¼ããèªãã ãããªãããå°ãã¥ã¤Rubyããªãã¸ã§ã¯ãæåã«ã¤ãã¦å¦ãã§ããã¾ãããããã£ãçãããªãåé¡ãèªåã§èª¿æ»ãããèãããããªãã解決ãã¦ãããã¨ã§ãç¾å ´åãéãããã¦ããã¾ãã
ãã£ã¨ã«ããã¼ããã£ã³ãã®è¯ãã¨ãã
ä¸è¨ã®ãå¼·ãã¡ã³ã¿ã¼ã«ãããç¾å ´åãéãããããã¨ããã®ãä¸çªã®é åã§ããä»ã«ãè²ã è¯ãæãããã®ã§åæãã¦ããã¾ãã
- 3ä¸å/æã§è¯å¿ç
- åæ¥çã¯çããæåãªä¼ç¤¾ã«å°±è·ããã¦ãï¼ãããããéãããããã¨ããã®ã¨äºäººã®äººèãåºãã¨ããã®ãããããï¼
- ãªã¢ã¼ãã§ã§ããï¼èªåã¯ç°èã«ä½ãã§ããã®ã§ãå®å ¨ã«ãªã¢ã¼ãã®ã¿ã§åæ¥ãã¾ããï¼
- ãã¼ã«ã«ã§ãã§ããï¼å¯è½ãªããã£ã¨ã«ãããã®ãªãã£ã¹ã«è¡ã£ãã»ããè¯ãã¨æãã¾ããSlackã§è³ªåããããç´ã§èãã»ãã便å©ã ããä»ã®çå¾ããããã¦ããæ°ãåºã¾ãï¼
- ç¹ã«å¼·å¶ããªããèªåã®ãã¼ã¹ã§é²ããããï¼äººã«ãã£ã¦ã¯ãã¡ãªããããï¼
- æ¥å ±ãå¦ç¿æéã®èãªã©ãå¦ç¿ãç¶ç¶ããããä¿ãä»çµã¿ããã
ãã£ã¨ã«ããã¼ããã£ã³ãã®æªãã¨ãã
æ£ç´ã»ã¨ãã©ãªãã®ã§ãããå ¬å¹³æ§ã®ããã«æªãã¨ãããããã¦ããã¾ãã
ãåºç¤ãæåã足åãæãã¦ããããªãããã¨ããã¨ããã¯äººã«ãã£ã¦ã¯è¾ãããã§ãã
ãã¶ãããã¯ãç¾å ´åãéãããããã®è£è¿ãã§ããç¾å ´åãéããããã«ã¯ãæªç¥ã®åé¡ã«åºä¼ã£ãæã«èªåã§è§£æ±ºããè½åãéãã¦ããå¿ è¦ãããã¾ãããã®ãããã£ã¨ã«ããã¼ããã£ã³ãã®èª²é¡ã¯ãèªåã§èª¿æ»ãã¦èãããã¨ãè¦æ±ãããçãã®ãªã課é¡ãå¤ãã§ãããªã®ã§Webã調ã¹ãããä»ã®çå¾ããã®æ¥å ±ã調ã¹ããããªãããèªåã®é ã§èãã¦è§£æ±ºãã¦ããã¾ãããã®èª¿æ»ã»æèèªä½ã大äºãªè¨ç·´ãªã®ã§ãããæªçµé¨è ã®å ´åã¯æåã足åãæãã¦æ¬²ããã¨ããæ¹ãããã¨æãã¾ããããããæ¹ã«ã¯ããã¾ãåãã¦ããªãããã¼ã¨æãã¾ãã
ããªããã¼ããªã«ãªãã¥ã©ã ã«ãªãã¾ãããå®éãã£ã¨ã«ããã¼ããã£ã³ããåæ¥ã§ãã人ã¯å°ãªãã§ããï¼ã ããããåæ¥çã¯çããåªç§ã ããæåãªä¼ç¤¾ããã«å°±è·ã§ããã®ã§ãããï¼
å人çã«ã¯åºç¤ã¯ç¬å¦ã§æ¸ã¾ãã¦ãããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã§ã¯ç¾å ´åãéããã¹ãã ã¨æãã®ã§ããã®ããæ¹ã¯æ£ããã¨æãã¾ããããã°ã©ãã¨ãã¦ã®é©æ£ãæ©ãã«å¤æã§ããã¨ããå©ç¹ãããã¾ããã¨ã¯ããæ©ãã«è±è½ãã¦ãã¾ã人ãçµæ§å¤ãã®ã§ãæªçµé¨è ã«ã¯ããã¡ãã£ã¨ãµãã¼ãããã£ã¦ãããã®ããªã¼ã¨ãæãã¾ãã
ããã¯æªãã¨ããã¨ããããææ³ã®åé¡ãããããªãã§ãã
ããã°ã©ãã³ã°æªçµé¨ã§ãã£ã¨ã«ããã¼ããã£ã³ãã«åå ãããæ¹ã¯ãProgateããããã¤ã³ã¹ãã¼ã«çã§å ã«åºç¤ãåå¼·ãã¦ãããã並è¡ãã¦åå¼·ãã¦ããã®ããããããã¾ãããã ã«ãªãã¥ã©ã çã«ã¯æªçµé¨ã§ãé²ããããããã«å¿ è¦ãªãã©ã¯ãã£ã¹ãç¶²ç¾ ãã¦ããã®ã§ãããæ°ãããæ¹ãªããã£ã¨ã«ããã¼ããã£ã³ãã ãã§ãåé¡ãªãã§ãã
ãã£ã¨ã«ããã¼ããã£ã³ãã«åãã¦ãã人
ãæä½éã®ããã°ã©ãã³ã°ã®åºç¤ç¥èããã£ã¦ãç¾å ´åãéãããæ¹ãã§ããå ·ä½çã«ã¯
- Progateããããã¤ã³ã¹ãã¼ã«çã§åºç¤ãç¬å¦æ¸ã¿ã®æ¹
- ä»ã®ããã°ã©ãã³ã°ã¹ã¯ã¼ã«ãåæ¥ãããã©å°±è·ã§ããªãã£ãæ¹
- SIerããWebç³»ã«è»¢è·ãããæ¹
- ç¾å½¹ããã°ã©ãã§ãRuby/Railsããã£ã¤ãåå¼·ãããæ¹
æå¤ããã§ãããç¾å½¹ã®ããã°ã©ããåå ããã®ã¯ãã£ã¡ãæãã ã¨æã£ã¦ãã¾ããèªåã¯Railsã®å®åçµé¨3~4å¹´ã§åå ãã¾ããããããã§ãå¦ã¶ãã¨ã大éã«ããã¾ãããï¼èªåã®Railsåãä½ãã¨ããã®ãããããã§ã ð¹ï¼ãçµé¨è ã®å ´åã¯ä¸è¦ãªãã©ã¯ãã£ã¹ã¯é£ã°ãã¤ã¤ãèªåãå¼·åãããåéãéç¹çã«ããã¾ããèªåã®å ´åã¯è¦ææèããã£ããã¹ãã¨ã¢ãã³ããã³ãã¨ã³ããéç¹çã«ããã¾ããã
ããã3æ¥é以å ã ã£ããç¡æã§è¾ããããã¯ããªã®ã§ãä¸åº¦å ¥ã£ã¦ã¿ã¦åããªãããªãè¾ãã¦ã¿ãã®ãããã¨æãã¾ãã¼ã
ãã®ä»ã®è¯ãããã°ã©ãã³ã°ã¹ã¯ã¼ã«ã®æ¢ãæ¹
å®éç¾å ´ã§åãã¦ããç¾å½¹ããã°ã©ãããã«èãã®ãä¸çªã§ããç¥ãåãã®ããã°ã©ãã«èããããåå¼·ä¼ã«åå ãã¦æ親ä¼ãªã©ã§èãã¦ã¿ãã®ãããã®ããªã¼ã¨æãã¾ããæ¡ç¨ã«é¢ãã£ã¦ããæ¹ãå¤ãã§ããããããã«ã¯åºã¦ããªããªã¢ã«ãªè©±ãèããã¨æãã¾ãã
æ¤ç´¢ã§è©å¤èª¿ã¹ãã®ã¯ã¤ãã¤ãããã§ããSEOãããã¯ããã¦ããã®ã§ãæçãªæ å ±ãæ¾ãã®ãé£ããã§ããä¾ãã°ãããã°ã©ãã³ã°ã¹ã¯ã¼ã« è©å¤ãã§æ¤ç´¢ããã¨ãç¾å½¹ããã°ã©ãããã®æªè©ãå¤ãããã°ã©ãã³ã°ã¹ã¯ã¼ã«ãæ¸ããè¨äºãåºã¦ãã¦ãèªåã§èªåããããããã¦ã¾ããæ¤ç´¢ã使ãå ´åã¯ãå人ããã°ã®ãªã¢ã«ãªå£°ãåèã«ããã¨ããããã§ãã
大å¦é¢ãããã
ãã¨ãããã°ã©ãã³ã°ã¹ã¯ã¼ã«ä»¥å¤ã®é¸æè¢ã¨ãã¦å°éè·å¤§å¦é¢ã«è¡ãã®ããªã¹ã¹ã¡ã§ãã¼ã
èªåã¯æ系大å¦ããããã°ã©ãã³ã°æªçµé¨ã§ç£æ¥æè¡å¤§å¦é¢å¤§å¦ï¼AIITï¼ã¨ããå°éè·å¤§å¦é¢ã«è¡ãã¾ãããå ¬ç«ãªã®ã§å®ãã§ããã社ä¼äººãéããããã«å¹³æ¥å¤ã¨åææ¥ã«éè¬ãã¦ããããæªçµé¨ã§ãï¼ã®ãªã®ãªï¼ã¤ãã¦ãããããã«ã«ãªãã¥ã©ãä½ããã¦ãã¾ãã
å ¥è©¦ã¯å¿ç¨æ å ±æè¡è 試é¨ã®ååç¸å½ã®åé¡ã§ã対çãç«ã¦ãããããã»ã©é£ããããã¾ããããã ãå ¥è©¦ã«æ¯ã¹ã¦çå¾ãæå¡ã®ã¬ãã«ã¯é«ãã®ã§ãå ¥å¦å¾ã¯ãªããªã大å¤ã§ãã
ã«ãªãã¥ã©ã ã¨ãã¦ã¯CSã®åºç¤ããããã¶ã¤ã³ãããã¸ã¡ã³ããçµå¶ã¾ã§åºãå¦ã¹ã¾ããèªåã¯CSé¢ä¿ã®è¬ç¾©ãã¨ãã ãã§æä¸æ¯ã§ãããããã¨2å¹´ç®ã¯PBLã¨ããå½¢ã§å®åç¸å½ã®çµé¨ãã¤ãã¾ãããããªãå®åã«å³ããå¦ã³ãå¯è½ã§ãã
2å¹´ããã¦ãã£ããå¦ã¹ã¾ããããã¡ããããªãããããã§ãã
ãã Railsã®ã¹ãã·ã£ãªã¹ããæãã¦ãããããã§ã¯ãªãã®ã§ãRailsãããã¨æ±ºãã¦ãããªããã¯ããã£ã¨ã«ããã¼ããã£ã³ããä¸çªããããã§ãã¼ãRuby/Railsã®æè²ã«é¢ãã¦ã¯ãããããããã£ã¨ã«ãããã¯è¯ãã§ã ð
mofmof inc.ããã«ã¤ãã¦èª¿ã¹ã¾ããã¼ð
以åä¼ç¤¾ä½é¨ä¼ã«åå ããã¦ããã ããmofmofããã«é¢è«ãã¦ããã ãããã¨ã«ãªãã¾ããã¼ã
èªåã¯æ°åæã¯å¤§å¦é¢ã®å人ã®ä¼ç¤¾ã«å°±è·ãã¦ãããªã¼ã©ã³ã¹æ代ãç¹ããã§ãä»äºãããã£ã¦ããã®ã§ãããããã¾ã¨ããªé¢è«ã¿ãããªã®ã¯ãããã¨ãããã¾ããããªã®ã§ã ãã¶ç·å¼µãã¾ãã
é¢è«ã®åæºåã¨ãã¦ããã®ä¼ç¤¾ãç¥ãããã«ä¼æ¥ç 究ããã£ã¦ããã¨ããããã§ããmofmofããã¯æåãªä¼ç¤¾ãªã®ã§ã ãããã©ããªä¼ç¤¾ãã¯ç¥ã£ã¦ãã¾ããããä»åã¯ãã詳ãã調ã¹ã¦ã¿ã¾ããã
ãä¸è©±ã«ãªã£ã¦ãããã£ã¨ã«ããã¼ããã£ã³ãããã«ä¼æ¥ç 究ã¨ãããã©ã¯ãã£ã¹ãããããã¡ããåèã«ãã¦ãã¾ãã
ï¼ããã¾ã§èªåç¨ã«ã¾ã¨ããã¡ã¢ã§ããããããèªåã®åéããªã©ãçµæ§æ··ãã£ã¦ããã¨æãã¾ãã®ã§ãæ£ç¢ºãªæ å ±ã«ã¤ãã¦ã¯mofmofããã®HPãä¼æ¥ããã°ã御覧ãã ãããï¼
代表
- åç°æ¦ãã
- twitterã¯@harada4atsushi
- ç¾å½¹ã¨ã³ã¸ãã¢ãTwitterãè¦ã¦ãã¨Railsã ãã§ãªãããã³ãã¨ã³ã/iOS/Android/æ©æ¢°å¦ç¿ãªã©ãªãã§ããã£ã¦ãããããã
- ã¢ã¸ã£ã¤ã«ã²ããã¯ã©ãã®ä¸»å¬ãããã¦ã
- ã¨ã³ã¸ãã¢ã®æ¹ã®ã¿ã©ã¼ã¡ã³é¸èãã£ã¦ãããã§ãã楽ãããã
- ããµããµå¥½ããããµããµå¥½ãã«æªã人ã¯ããªãã¨èã
ããã·ã§ã³ã»ãã¸ã§ã³ã»ããªã¥ã¼
ããã·ã§ã³
- æ°ãããã¯ããã¸ã¼ã使ã£ã¦æ°ãã価å¤ãåµé ããããä¸è¬çãªãã®ã«å¤ãããã¨
- ãæè¡ãç®çããã¸ãã¹ã¯æ段ãã¨ãã価å¤è¦³ãæè¡å¥½ããä¼ãã£ã¦ãã¾ãããã¦ãã
ãã¸ã§ã³
- ã¤ãã£ã¦äººãããããã«ãã
ããªã¥ã¼
- æ ¹æ§ã«é ¼ãããæèãã¦å·¥å¤«ãã
- ãã¾ããããªãã¨ãã¯ã人ãã§ã¯ãªããä»çµã¿ãã«çç®ãããã¨
- ææ çã«ãªããªããã¨
- èªå·±ç é½ãããã¨
- ä¼ç¤¾ã®ããã§ã¯ãªãèªåã®ããã«åããã¨
åè
- mofmofのミッション | 月額制受託開発の株式会社mofmof
- もふもふな5つの価値観 | 月額制受託開発の株式会社mofmof
- mofmof inc.入社ガイド。これから入社するあなたへ。 - 毎日がもふもふ
ã¡ã³ãã¼æ§æ
- 20åç¨åº¦
- 社å¡ããã¨ããªã¼ã©ã³ã¹ããåã ããã
- 20代ã¨30代ãåã ããã
- 8å²ãã¨ã³ã¸ãã¢
- å¼·ãã¨ã³ã¸ãã¢ãå¤ã
- ãã¶ã¤ãããã¯ããªã
åãç°å¢
- æ£ç¤¾å¡/æ¥åå§è¨
- å¯æ¥ãæçããµãã¼ã
- ç«ææ¥ã¯ãªã¢ã¼ãã¯ã¼ã¯
- ã¬ãã§æ®æ¥0
- ãã³ãã£ã¼ä¼æ¥ã«ãããã¡ãªããªããªããé°å²æ°ã¯ãªããã¨ã³ã¸ãã¢ã«ã¨ã£ã¦å± å¿å°ãè¯ãç°å¢ãã¤ã¤ãã³çç¨å¯ã§ä½æ¥ã«æ²¡é ãããã
- ã¡ã³ãã¼ã¯React.jsåå¼·ä¼ããåå¿è åãæ©æ¢°å¦ç¿åå¼·ä¼ãVue.jsåå¼·ä¼ãªã©ã社å å¤åãã«åå¼·ä¼ãç©æ¥µçã«éå¬
- 1人ã§2æ¡ä»¶æã¤ãã¨ãããã®å ´åã¯20æé/é±ã2ã¤æã¤æãã«ãªããåå/åå¾ã§åãã¦ãããããæ¥ã«ã¡ã§åãã¦ãè¯ããããã®è¾ºã¯èªç±ã
- ã¯ã©ã¤ã¢ã³ã(ãããã¯ããªã¼ãã¼)ãå«ãã¦2ã6åãããã®å°è¦æ¨¡ãã¼ã ã§éçº
- ããªã¼ã©ã³ã¹ããã§ã社å¡ããã§ã2.5æ¥/é±ããå ¥ãããããªã¼ã©ã³ã¹ã®å ´åã¯åºæ¬çã«ã¯2.5æ¥/é±ããã¹ã¿ã¼ãããã
- åè¨ã§ã客å 常é§ã¯ãªãã社å ã§éçº
- ãæ¼ä¼ã¿ã¯ã¿ããªã²ã¼ã ãã¦ã
åè
- どんな風に働いているか | 月額制受託開発の株式会社mofmof
- 機能積み上げ見積もりはやめて、マイルストーン逆算見積もりをしよう | 月額制受託開発の株式会社mofmof
- 社長が夏休みを取った日に、いつもより終業後の社内が賑わっていた話 | 株式会社mofmof
- お昼休みってどう過ごしてる?〜mofmofのお昼リポート〜 | 株式会社mofmof
ããã°ã©ãã³ã°
- ã³ã¼ãã¬ãã¥ã¼ã¯å¿ é
- ãã¹ãã³ã¼ãã¯å¯è½ãªéãæ¸ã
- TDDæ¨å¥¨
å©ç¨ãã¦ããæè¡
ãµã¼ããµã¤ã
ã¤ã³ãã©
- Heroku or AWS(åºæ¬ããã以å¤ã¯å注ãã¦ããªã)
ããã³ãã¨ã³ã
- Vue.jsãã¡ã¤ã³ãNuxt.jsã使ã£ã¦ãã£ã½ãã
- React.jsãã
- jQueryã¯ãã使ã£ã¦ãªãããã
ãã¼ã«ãªã©
åå常ã«ææ°ãã¼ã¸ã§ã³ã«ã¢ããã°ã¬ã¼ããã
äºæ¥å 容
åè¨éçº
æé¡å¶åè¨éçºãéçºãã¼ã ã¬ã³ã¿ã«ã
- (ãããã)ã¡ã¤ã³ã¨ãªãåè¨ãµã¼ãã¹
- æãªããã®ã¦ã©ã¼ã¿ã¼ãã©ã¼ã«åã®ä½ã£ã¦çµããã®åè¨ã§ã¯ãªããæé¡å¶ã¢ã¸ã£ã¤ã«åã®åè¨
- è«è² å¥ç´ã§ã¯ãªããæºå§ä»»å¥ç´
- 客å 常é§ã§ã¯ãªãã社å ã§éçº
- ææç©ã®å®ç¾ã§ã¯ãªãã価å¤ã®å®ç¾
- ã¯ã©ã¤ã¢ã³ãã¨ã¯å注è ã»çºæ³¨è ã®å¯¾ç«ã®é¢ä¿ã§ã¯ãªãã1ã¤ã®ãã¼ã ã¨ãã¦ã®é¢ä¿
- ã¾ãã¯MVPãä½ãã3ã¶æ以å ã«ãµã¼ãã¹ã¤ã³
- æ°è¦äºæ¥ã«ç¹å
- æµãã¯ãéçºç¸è« -> å¥ç´ -> éçº -> ãªãªã¼ã¹ -> ä¿å®
- ã¢ããªéçºããããWebéçºãã¡ã¤ã³
- å¶æ¥ã¯ãã¦ãªãã¦pullã®ã¿(ã¨èããæ°ããããåéããã)ãããã§ãã¨ã³ã¸ãã¢ã足ããªããªãã»ã©å¤æ°ã®ä¾é ¼ãæ¥ã¦ããã
- ç¾å¨ã¯20ç¨åº¦ã®æ¡ä»¶ãèµ°ã£ã¦ãã
- ä¾¡æ ¼
- 60ä¸/æãã(å¤ãè³æãªã®ã§å¤ãã£ã¦ãã)
- ä¿å®ã»éç¨ãã§ã¼ãºã¯3ä¸/æããã®å¥ãã©ã³ããããèå¼±æ§å¯¾å¿ããã£ãã対å¿çã
- éå»ã®äºä¾
- webä¸ã®é»åæ¸ç±ãµã¼ãã¹ https://www.yondemill.jp
- ãä¸äººæ§åãäºç´ãµã¼ãã¹: https://info.flatea.jp/
- ãã¸ãã¹ãã£ãã https://abejainc.com/platform/ja/
- çè·å¸«/è·å ´ãããã³ã°ãµã¼ãã¹ https://nadeshikonurse.jp
- ã·ã§ããã³ã°ã¢ã¼ã«ãµã¼ãã¹ https://rili.tokyo
åè
ãããªãMVP
- 3æ¥ã®éçºå宿ã§MVPãä½ããã
- 軽äºæ²¢ã¨ãè¡ãããããããã°ã§çãã楽ããã
- ãã®ãã¨éçºãã¼ã ã¬ã³ã¿ã«ã«ç¹ããã®ããª
- 250ä¸åãã
åè
- わずか3日でアプリ開発!いきなりMVP大成功! | 月額制受託開発の株式会社mofmof
- えっ、私のサービスできるの早すぎっ…mofmof噂の爆速開発を目撃! | 月額制受託開発の株式会社mofmof
ãããªãã·ã§ã¢ãªã³ã°ã¨ã³ããã¼
- ãããªãMVP + ã·ã§ã¢ãªã³ã°ã¨ã³ããã¼ã¹ã¿ã¼ã¿ã¼ããã±ã¼ã¸
My-ope office
- 社å åãåãã対å¿å°ç¨ã®AIãã£ããããã
- 社å ããã®åãåããã«ããã³ã¹ããæ¸ããã
æ°è¦äºæ¥
- ãæè¡ãç®çããã¸ãã¹ã¯æ段ãã®è¨èéããAR/VR/AIãªã©ã®æ°ããæè¡ã使ã£ãäºæ¥ãå¤ã
meshiqoo
- ARã§é£²é£åºãæ¤ç´¢
- ãã¦ã³ãã¼ããã¦ä½¿ã£ã¦ã¿ãããæç¥çã®ç°èã«é£²é£åºãªãã¦ãªãã£ãð¢æ±äº¬è¡ã£ãã使ãã
VRé å±
- VRå ã§ãé ãè²·ãã
Toriders
- AIã«ããæ¯ãè¾¼ã¿æ¥åèªååãµã¼ãã¹
æ¡ç¨åºæº
- 主ã«æè¡å/人éæ§/ã³ãã¥ãã±ã¼ã·ã§ã³è½åã®3ã¤
人éæ§
- mofmofã®ãã¸ã§ã³ãããã·ã§ã³ã«å ±æã§ãã人
- æè¡å¥½ããªäººãWEBãµã¼ãã¹ããããã¯ããä½ãã®ã好ããªäººã
- å¦ç¿ãç¶ãããã人ãå¦ç¿ã楽ããã人ãèªãå¦ã¹ã人ã
- ææ çã«ãªããªã人ã波風ãç«ã¦ãªã人
- ãã ä½ãã®ã§ã¯ãªããã¯ã©ã¤ã¢ã³ãã«å¯¾ãã¦ã¡ããã¨ä¾¡å¤ãæä¾ã§ãã人
- èªå¾çã«è¡åã§ãã人
- åçãæ¹åãç¶ãã人
- æé«ã®ä»²éï¼çãªæè¦ãã人ã¯ã¡ãã£ã¨éãããã
åè
ã³ãã¥ãã±ã¼ã·ã§ã³è½å
- ç´ æ©ãé©åã«ä»è ã¨ææçéãåæããè½å
- ä¼è©±ãæ¯ãèãã«ãã£ã¦ä»è ã«å¥½æãä¸ããè½å
åè
ç¦å©åç
- åºå¼µãããµã¼ã¸
- æ¸ç±ãªã¯ã¨ã¹ã
- GPUæå½ãã¯ã©ã¦ããèªè²»è³¼å ¥ã®ã°ã©ãã®è²»ç¨ã®ä¸é¨ãä¼ç¤¾ã§è² æ ãAI使ã£ãèªä½ãµã¼ãã¹ä½ãéã«GPUé«ãã¦è¦å´ããã®ã§ãããã¯å¬ãã人å¤ãã
- Herokuã®Dynoæå½
- ããµããµæå½ãããµããµé¢ä¿ã§è²°ããã
åæ¥ä»ç¤¾ããã¨æ¯ã¹ãéã®ç¹å¾´
- Railsã«ããã¢ã¸ã£ã¤ã«éçºã§ãåã«ä½ã£ã¦çµããã§ã¯ãªãã¯ã©ã¤ã¢ã³ãã¸ã®ä¾¡å¤æä¾ãéè¦ãã
- æ°è¦äºæ¥ã«ç¹åãã¦ãã¦0->1ãçµé¨ã§ãã
- ã¯ã©ã¤ã¢ã³ã(ãããã¯ããªã¼ãã¼)ãå«ãã¦2ã6åãããã®å°è¦æ¨¡ãã¼ã
- ããªã¼ã©ã³ã¹ãããå¤ãã社å¡ããããããªãæãããã®ã§
- åè¨éçºã¨æ°è¦äºæ¥ã®ä¸¡è¼ª
- 2.5æ¥/é±ããå ¥ãããé±1ãªã¢ã¼ãã¯ã¼ã¯çã®åãããã
- ãæè¡ãç®çããã¸ãã¹ãæ段ãçã®ã¦ãã¼ã¯ãªä¾¡å¤è¦³
- mofmofæãHRTãç©ããããåªç§ããæè¡å¥½ãããã®ã¥ãã好ããåç©å¥½ãçãªãï¼ããã°ããåããå°è±¡ã§ãï¼
ä¼æ¥ç 究ãã¦ã¿ãææ³
åç´ã«ä¼æ¥ããã°ã社é·ã®åç°ããã®ããã°ãåå¼·ã«ãªãã¾ããâ¨
åç°ããã®ããã°ã¯ä»¥åããèªã¾ãã¦ããã£ã¦ãã¦ãèªåãèªä½ã¢ããªãä½ã£ãéã«ãã¨ã¬ãã¼ã¿ã¼ããããä½ãæã« エレベーターピッチの作り方 - シンプルな言葉でプロダクトを表現する方法 - 毎日がもふもふ ãåèã«ããã¦é ãã¦ã¾ãããä»ã®è¨äºãç¾å³ããæ å ±ãè©°ã¾ã£ã¦ããã®ã§ãmofmofå¿æãããªãæ¹ã«ãããããã§ããæè¡ç³»ã®è¨äºã¯æ®æ®µããèªãã®ã§ããããã¸ãã¹å¯ãã®è¨äºã¯ãã¾ãèªãã§ããªãã£ãã®ã§ç¥è¦ã®å¡ã§ãããããªãæ å ±éãå¤ãå ¨ç¶æ¶åã§ãã¦ãªãã®ã§ãä½åº¦ãèªã¿è¿ããã¨ã«ãªãããã§ãã
ãã¨ãä¼æ¥ç 究ãã¦ã¿ã¦ãã¯ãmofmofããã¯èª¿ã¹ãã°èª¿ã¹ãã»ã©ããä¼ç¤¾ã ãªã¼ã¨æãã¾ãããåªç§ã§ãæè¡ã好ãã§ããã®ã¥ããã好ãã§ãåªããä¼ç¤¾ããã§ããå®éã«ç¤¾å¡ã®æ¹éã¨ã話ããã¦ããã ããéãåããã¨æãã¾ããã(ãã ããã°ã ã¨ãããµããªé°å²æ°ã§ãããå®éã«ã¯ã¬ãã§å¼·ãã¨ã³ã¸ãã¢ããéã°ããã ã¨èãã¾ãã)
ãæè¡ãç®çããã¸ãã¹ãæ段ããããæ ¹æ§ã«é ¼ãããæèãã¦å·¥å¤«ãããçãä»ã®ä¼ç¤¾ã«ã¯ãªãã¦ãã¼ã¯ãªä¾¡å¤è¦³ãå¤ãããã¾ããåç°ãããSIer -> ããªã¼ã©ã³ã¹ã¨ããçµé¨ãããã¦ããã¨ã³ã¸ãã¢ãªã®ã§ãã¨ã³ã¸ãã¢ã価å¤ãå®ç¾ããªãã楽ãã¿æé·ãã¦ããã«ã¯ã©ãããã°ããã®ãï¼ã£ã¦ããçºæ³ãæ ¹ã£ãã«ããã®ããªã¼ã¨æ³åãã¾ãããããã£ã価å¤è¦³ã¯ãmofmofãã¨ããä¼ç¤¾åã«ç¾ãã¦ãæ°ããã¾ãã
åéãå¤ãã¦ç«¶äºçãé«ãã¨ããã話ãèãã®ã§æ£ç´èªåã®å®åã§ã¯é£ããæ°ããã¾ããããããããããããªã¼ã¨æãã¾ãð
åè
- TOP | 月額制受託開発の株式会社mofmof
- 株式会社mofmofの会社情報 - Wantedly
- 毎日がもふもふ
- mofmofコラム | 月額制受託開発の株式会社mofmof
- (旧)毎日がもふもふ - mofmof inc.のブログ
- もふもふ技術部(技術ブログ)やってます! | 株式会社mofmof
- mofmof inc.入社ガイド。これから入社するあなたへ。 - 毎日がもふもふ
- mofmof inc. 会社紹介 for 採用/mofmofinc-informatioin-for-recruiting - Speaker Deck
- サーバサイドも極めたい!スキルチェンジしたいiOSエンジニア募集! - 株式会社mofmofのWeb エンジニア中途・契約・委託の求人 - Wantedly