Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: a62c12d362
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 1415 lines (905 sloc) 55.803 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414

<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
  <meta charset="utf-8">
  <title>Shiny happy people coding</title>
  <meta name="author" content="Cyril Mougel">

  
  <meta name="description" content="A la sortie de
decent_exposure, j&#8217;ai été
très enthousiaste. J&#8217;utilisais avant
inherited_ressources, mais je
commençais à découvrir les &hellip;">
  

  <!-- http://t.co/dKP3o1e -->
  <meta name="HandheldFriendly" content="True">
  <meta name="MobileOptimized" content="320">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  
  <link rel="canonical" href="http://blog.shingara.fr/index.html">
  <link href="/favicon.png" rel="icon">
  <link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
  <script src="/javascripts/modernizr-2.0.js"></script>
  <script src="/javascripts/ender.js"></script>
  <script src="/javascripts/octopress.js" type="text/javascript"></script>
  <link href="/atom.xml" rel="alternate" title="Shiny happy people coding" type="application/atom+xml">
  <!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">

  
  <script type="text/javascript">
    var _gaq = _gaq || [];
    _gaq.push(['_setAccount', 'UA-11352302-1']);
    _gaq.push(['_trackPageview']);

    (function() {
      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
  </script>


</head>

<body >
  <header role="banner"><hgroup>
  <h1><a href="/">Shiny happy people coding</a></h1>
  
    <h2>Codons avec le sourire</h2>
  
</hgroup>

</header>
  <nav role="navigation"><ul class="subscription" data-subscription="rss">
  <li><a href="/atom.xml" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
  
</ul>
  
<form action="http://google.com/search" method="get">
  <fieldset role="search">
    <input type="hidden" name="q" value="site:blog.shingara.fr" />
    <input class="search" type="text" name="q" results="0" placeholder="Search"/>
  </fieldset>
</form>
  
<ul class="main-navigation">
  <li><a href="/">Blog</a></li>
  <li><a href="/blog/archives">Archives</a></li>
</ul>

</nav>
  <div id="main">
    <div id="content">
      <div class="blog-index">
  
  
  
    <article>
      
  <header>
    
      <h1 class="entry-title"><a href="/pourquoi-jai-arrete-decent-exposure.html">pourquoi j&#8217;ai arrêté decent_exposure</a></h1>
    
    
      <p class="meta">
        








  


<time datetime="2012-07-04T09:49:00+02:00" pubdate data-updated="true">Jul 4<span>th</span>, 2012</time>
        
         | <a href="/pourquoi-jai-arrete-decent-exposure.html#disqus_thread">Comments</a>
        
      </p>
    
  </header>


  <div class="entry-content"><p>A la sortie de
<a href="https://github.com/voxdolo/decent_exposure">decent_exposure</a>, j&#8217;ai été
très enthousiaste. J&#8217;utilisais avant
<a href="https://github.com/josevalim/inherited_resources/">inherited_ressources</a>, mais je
commençais à découvrir les problèmes de <code>inherited_resources</code>. La
personnalisation de son controller peut vite devenir compliqué et peux
lisible si on sort du cadre d&#8217;un controller qui soit plus qu&#8217;un CRUD
simple. On finissait par avoir un code moyennement
DRY et les test étaient loin d&#8217;être évident car impossible coté controller
( limitation indiqué dans le README lui-même ).</p>

<p>Le grand avantage que j&#8217;ai vu dans <code>decent_exposure</code> est la facilité
d&#8217;accès des variables dans les vues. Plus besoin de faire appel à des
instances. On appele simplement la méthode. Si celui-ci n&#8217;était pas
instancié alors <code>decent_exposure</code> le faisait pour nous. On obtenait ainsi un système beaucoup plus souple qui ne
chargeait les objets qu&#8217;au moment ou il était nécessaire. Un eager
loading intégré permettait d&#8217;éviter de rechercher en base plusieurs fois
le même objet. On pouvait aussi réutiliser plusieurs fois la même vue.
plus besoin de faire des assignations dans certaine action pour être sur
que l&#8217;objet existe. Il suffit juste d&#8217;exposer l&#8217;objet. Après on
l&#8217;utilise ou pas. De même l&#8217;utilisation des partials devient plus aisé
car, on peux surcharger facilement des variables par l&#8217;usage des
<code>locals</code>. J&#8217;y ai vu beaucoup d&#8217;intérêts.</p>

<p>Mais finalement cet intérêt n&#8217;existe que par l&#8217;usage de la méthode de
class d&#8217;un controller <code>helper_method</code>. Si on crée soit même sa propre
méthode avec son eager loading <code>decent_exposure</code> devient inutile.</p>

<p><code>decent_exposure</code> a été pour moi un révélateur de l&#8217;utilité de la
méthode <code>helper_method</code>. Mais à l&#8217;usage, je trouve qu&#8217;il fait
finalement trop de chose caché si on utilise la méthode d&#8217;appel <code>expose</code>
sans bloc. Je me suis ainsi retrouvé à faire des <code>update_attributes</code> 2
fois sur mon objet. Un dans le <code>decent_exposure</code> l&#8217;autre dans mon
action. Forcement ça posait quelques soucis. Quand on sait que cela peut
arriver, pas de soucis. Mais c&#8217;est toujours embêtant de perdre quelques
heures à débugger le problème quand on le voit. Sans compter les fois ou
on ne le voit pas.</p>

<p>Une des limitations de <code>decent_exposure</code> selon moi est l&#8217;override de
cette méthode. Parfois pour éviter les <code>if</code> infini dans cette méthode il
est plus judicieux de définir directement la valeur de retour de cette
méthode dans sa méthode d&#8217;action. Cela permet de savoir exactement ce
que retourne cette méthode, mais aussi d&#8217;éviter les conflits dans
d&#8217;autre action.</p>

<p>Pour réalisé cela ma méthode stocke en mémoisation la variable
d&#8217;instance égale au nom de la méthode. Ainsi ma méthode ressemble à ceci
:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">post</span>
</span><span class='line'> <span class="vi">@post</span> <span class="o">||=</span> <span class="no">Post</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">params</span><span class="o">[</span><span class="ss">:id</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'><span class="n">helper_method</span> <span class="ss">:post</span>
</span></code></pre></td></tr></table></div></figure>


<p>Si je souhaite donc avoir un nouveau Post retourné par cette méthode
j&#8217;ai juste à faire :</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">new</span>
</span><span class='line'> <span class="vi">@post</span> <span class="o">=</span> <span class="no">Post</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Je surcharge le retour de la méthode post par la valeur <code>Post.new</code>. Pour
faire cela avec <code>decent_exposure</code> il faut surchargé la variable
<code>@_resource[:post]</code>. Mais rien ne m&#8217;assure que ce nom de variable d&#8217;instance
soit conservé dans les futurs version de <code>decent_exposure</code>. Une solution serait peut-être de créer une
méthode <code>post=()</code> lors de l&#8217;exposition d&#8217;un <code>post</code>, mais cela devient
peut-être moins pratique.</p>

<p>Voilà donc les raisons de mon arrêt d&#8217;utilisation de <code>decent_exposure</code>.
Je peux très facilement émuler le comportement de <code>decent_exposure</code> et
tout ça sans aucune dépendance externe.</p>
</div>
  
  


    </article>
  
  
    <article>
      
  <header>
    
      <h1 class="entry-title"><a href="/tester-ses-vues-rabl.html">tester ses vues rabl</a></h1>
    
    
      <p class="meta">
        








  


<time datetime="2012-06-28T09:40:00+02:00" pubdate data-updated="true">Jun 28<span>th</span>, 2012</time>
        
         | <a href="/tester-ses-vues-rabl.html#disqus_thread">Comments</a>
        
      </p>
    
  </header>


  <div class="entry-content"><p>Personnelement, quand je fais des API, j&#8217;utilise le gem
<a href="https://github.com/nesquena/rabl">Rabl</a>. Je trouve ce gems vraiment
génial. Avant son utilisation, je faisais mes API json avec la méthode
<code>#to_json</code>. Mais pour ceux qui l&#8217;on utilisé, vous savez que c&#8217;est un
enfer à maintenir. Surtout si vous avez plusieurs type de représentation
de votre objet à différent endroit.</p>

<h1>Rabl la simplicité d&#8217;expression</h1>

<p>Pour gérer ses vues en JSON ou XML, les gems classique sont <code>JBuilder</code>
et <code>XmlBuilder</code>. Deux gems réalisées par DHH. Mais, personnelement, je
les trouves assez verbeuses comme vues. A contrario, Rabl a une syntaxe
trés simplifiée. On peux ausi avoir un système de partial qui permet une
réutilisation compléte. Petit bonus par rapport à JBuilder/XmlBuilder
est qu&#8217;il utilise la même vue pour générer du XML ou du JSON. Donc pas
besoin de faire plusieurs vues en fonction du format de sortie.</p>

<p>Voici un example de vue Rabl :</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">object</span> <span class="vi">@post</span>
</span><span class='line'><span class="n">attribute</span> <span class="ss">:content</span>
</span><span class='line'><span class="n">child</span><span class="p">(</span><span class="ss">:author</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'> <span class="n">attribute</span> <span class="ss">:firstname</span><span class="p">,</span> <span class="ss">:lastname</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h1>Tester sa vue Rabl</h1>

<p>Pour tester le résultat de cette vue Rabl, deux possibilités s&#8217;offre à
nous. Un test de la génération de la vue par un test d&#8217;intégration
couplé avec le test du controller, soit un test de la vue. Finalement
tester une vue Rabl c&#8217;est ni plus ni moins que tester un retour de la
méthode <code>#to_json</code>. Donc si nous testons notre vue directement à partir
des données passées, c&#8217;est plus rapide et plus unitaire.</p>

<p>Depuis la version 0.6.0 de Rabl, une méthode permet de générer la vue
directement. C&#8217;est cela que nous allons utiliser pour faire notre test
de vue.</p>

<p>Voici donc un test de notre vue ( défini dans
<code>spec/views/posts/show_rabl_spec.rb</code> )</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;spec_helper&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="n">describe</span> <span class="s2">&quot;blogs/show.rabl&quot;</span> <span class="k">do</span>
</span><span class='line'>
</span><span class='line'> <span class="n">let</span><span class="p">(</span><span class="ss">:auhor</span><span class="p">)</span> <span class="p">{</span> <span class="no">Author</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:firstname</span> <span class="o">=&gt;</span> <span class="s1">&#39;Cyril&#39;</span><span class="p">,</span> <span class="ss">:lastname</span> <span class="o">=&gt;</span> <span class="s1">&#39;Mougel&#39;</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'> <span class="n">let</span><span class="p">(</span><span class="ss">:blog</span><span class="p">)</span> <span class="p">{</span> <span class="no">Blog</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:content</span> <span class="o">=&gt;</span> <span class="s1">&#39;hello&#39;</span><span class="p">,</span> <span class="ss">:author</span> <span class="o">=&gt;</span> <span class="n">author</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'> <span class="n">let</span><span class="p">(</span><span class="ss">:valid_json</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="ss">:content</span> <span class="o">=&gt;</span> <span class="n">blog</span><span class="o">.</span><span class="n">content</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:author</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span><span class='line'> <span class="ss">:firstname</span> <span class="o">=&gt;</span> <span class="n">author</span><span class="o">.</span><span class="n">firstname</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:lastname</span> <span class="o">=&gt;</span> <span class="n">author</span><span class="o">.</span><span class="n">lastname</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span><span class="o">.</span><span class="n">to_json</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="n">let</span><span class="p">(</span><span class="ss">:render</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="no">Rabl</span><span class="o">.</span><span class="n">render</span><span class="p">(</span>
</span><span class='line'> <span class="n">blog</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;blog/show&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:view_path</span> <span class="o">=&gt;</span> <span class="s1">&#39;app/views&#39;</span>
</span><span class='line'> <span class="p">)</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="n">it</span> <span class="s1">&#39;should render valid_json&#39;</span> <span class="k">do</span>
</span><span class='line'> <span class="n">render</span><span class="o">.</span><span class="n">should</span> <span class="n">eql</span><span class="p">(</span><span class="n">valid_json</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>On obtient ainsi un test unitaire vraiment simple et une validation
compléte du json obtenu. Le test est vraiment très rapide et n&#8217;est pas
pollué par le test du controller.</p>

<p>J&#8217;ai par contre découvert des limitations à ce test car, on ne peux
passer à la méthode <code>#render</code> que les objects définis par <code>object</code> ou
<code>collection</code>. Si on veux tester une vue rabl qui utilise plusieurs
variables, la tâche devient très hardu. J&#8217;ai donc commencé à proposer un
<a href="https://github.com/nesquena/rabl/pull/269">Pull Request</a> pour passer directement des variables dans sa vue Rabl, de
la même méthode que les partials avec l&#8217;options <code>:locals</code>. Vous pouvez
la <a href="https://github.com/nesquena/rabl/pull/269">suivre sur github</a></p>

<p><a href="http://blog-en.shingara.fr/test-your-rabl-view.html">English translation</a></p>
</div>
  
  


    </article>
  
  
    <article>
      
  <header>
    
      <h1 class="entry-title"><a href="/vundle-ou-le-bundler-de-vim.html">vundle ou le bundler de vim</a></h1>
    
    
      <p class="meta">
        








  


<time datetime="2012-05-24T09:40:00+02:00" pubdate data-updated="true">May 24<span>th</span>, 2012</time>
        
         | <a href="/vundle-ou-le-bundler-de-vim.html#disqus_thread">Comments</a>
        
      </p>
    
  </header>


  <div class="entry-content"><p>Personnellement, j&#8217;utilise vim comme éditeur de texte depuis mon
école. J&#8217;ai toujours apprécié vim et je ne compte toujours pas changer
d&#8217;éditeur.</p>

<h1>Mon évolution de la gestions des plugins vim.</h1>

<p>Vim a une très grande quantité de plugins disponibles et il est très
rapidement indispensable d&#8217;en utiliser plusieurs. La gestion des plugins
est donc très importante. Au fil des années, j&#8217;ai changé de technique en
fonction des possibilités apportées par vim ou par les développeurs.</p>

<h2>Gestion manuelle</h2>

<p>Au début, je gérais manuellement mes plugins en les ajoutant dans les
dossiers correspondant. Je versionnais mon dossier <code>.vim</code> et <code>.vimrc</code> et je pouvais le faire
évoluer globalement. Le soucis de cette technique est qu&#8217;il est pas
forcement évident de gérer les mises à jour des plugins et leur
installation n&#8217;est pas forcement simple car il faut mettre plusieurs
fichiers à plusieurs endroits.</p>

<h2>L&#8217;arrivée des vimballs</h2>

<p>Dans une évolution de vim, il y a eu la possibilité de gérer des
vimballs. L&#8217;avantage de cette technique est qu&#8217;on avait moins de
problème lors de l&#8217;installation et on pouvait gérer un peu plus
facilement les mises à jour car on savait rapidement quelle version on
utilisait. Mais la encore il fallait allez régulièrement sur
vimscript.org
pour voir si nos plugins avaient changé de version. Chose que finalement
on faisait très peu au final.</p>

<h2>Gestion par git-submodule</h2>

<p>Avec l&#8217;arrivée de github, les choses ont pu changer. Les plugins vim ont
commencé à avoir un dépôt centralisé, on pouvait suivre directement
l&#8217;évolution des scripts. Même vimscript a converti tous les plugins
qu&#8217;il hébergeait en repository git. Maintenant on peux gérer tous ses plugins
en faisant des mises à jour de repository git. J&#8217;ai ainsi commencé a gérer des
submodule et des liens symboliques vers ces submodules. La mise à jour
était automatique, mais l&#8217;installation devenait encore plus compliqué
qu&#8217;avant.</p>

<h2>Janus, la distribution vim</h2>

<p>C&#8217;est alors que Yehuda Katz et Carl Lerche ont commencé à créer
<a href="https://github.com/carlhuda/janus">janus</a>. Ce projet se veut comme une
distribution de gestion de plugins vim. Il contient un jeu de tâche rake
qui permette de mettre à jour facilement ses plugins. Un <code>.vimrc</code> est aussi
fourni pour utiliser les plugins par défaut et ajouter une configuration
minimal pratique. Ce projet est vraiment génial pour commencer à
pratiquer vim. On peux ainsi avoir un jeu de plugins pratique et
intéressant. Par contre, la gestion des versions de janus avec ses
propres usage peux vite devenir compliquée. En gros c&#8217;est bien si on ne veut
jamais modifier sa conf vim.</p>

<h2>Pathogen, le premier plugin vim de gestions de ses plugins</h2>

<p>Très peu de temps après <a href="https://github.com/tpope">Tim Pope</a> ( très prolifique développeur de plugins
vim ) a sorti <a href="https://github.com/tpope/vim-pathogen">Pathogen</a>. Ce
plugin permet de gérer directement la gestion de ses plugins dans son vimrc. J&#8217;avoue ne pas avoir
trop regardé comment fonctionne ce plugin. On m&#8217;en a toute fois dit du
bien. Il y a eu pas mal de projet pour que janus utilise pathogen
typiquement.</p>

<h2>Vundle, le bundler de vim.</h2>

<p>Mais c&#8217;est là qu&#8217;on m&#8217;a parlé du plugin qui me semble le meilleur
actuellement concernant la gestion de ses plugins vim,
<a href="https://github.com/gmarik/vundle">Vundle</a>. Comme pathogen, la gestion
des plugins est faite directement dans son vimrc. Son usage y est très
simplifié et pratique. Si vous connaissez
<a href="http://gembundler.org">Bundler</a> alors vous comprendrez facilement sont
usage car il en est très inspirés.</p>

<h1>Utilisation de Vundle</h1>

<h2>Installation de Vundle</h2>

<p>Pour installer vundle, un simple clone du repository du projet et 2
lignes dans votre <code>.vimrc</code> suffisent.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>git clone https://github.com/gmarik/vundle.git ~/.vim/bundle/vundle</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='vim'><span class='line'><span class="k">set</span> <span class="nb">rtp</span><span class="p">+=~</span><span class="sr">/.vim/</span>bundle<span class="sr">/vundle/</span>
</span><span class='line'><span class="k">call</span> vundle#rc<span class="p">()</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Configuration de ses plugins</h2>

<p>Pour utiliser vundle une fois installé. C&#8217;est extrêmement simple. il
suffit d&#8217;utiliser la commande <code>Bundle</code> et le chemin de votre plugin.
Ainsi pour installer le plugin <code>vim-rails</code> il suffit juste de faire :</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='vim'><span class='line'>Bundle <span class="s1">&#39;tpope/vim-rails.git&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Installation de ses plugins</h2>

<p>Ensuite, une fois votre vim lancé deux commandes vous suffisent.
<code>BundleInstall</code> qui permet d&#8217;installer tous les plugins que vous avez
définis et <code>BundleInstall!</code> qui permet de les mettre à jour.</p>

<p>Désormais ils ne vous reste plus qu&#8217;à trouver les plugins que vous
souhaitez et les utiliser.</p>

<h1>Mon vimrc</h1>

<p>Si vous souhaitez découvrir mon usage de vim, <a href="https://github.com/shingara/vim-conf">mon vimrc est ainsi
disponible sur github</a>. Grâce à
Vundle rien de plus simple que de le lire et découvrir rapidement les
plugins vim que j&#8217;utilise.</p>

<p><a href="http://blog-en.shingara.fr/vundle-the-bundler-of-vim.html">English Translation</a></p>
</div>
  
  


    </article>
  
  
    <article>
      
  <header>
    
      <h1 class="entry-title"><a href="/dante-pour-mettre-du-daemon-dans-son-code.html">dante pour mettre du daemon dans son code</a></h1>
    
    
      <p class="meta">
        








  


<time datetime="2012-05-09T09:43:00+02:00" pubdate data-updated="true">May 9<span>th</span>, 2012</time>
        
         | <a href="/dante-pour-mettre-du-daemon-dans-son-code.html#disqus_thread">Comments</a>
        
      </p>
    
  </header>


  <div class="entry-content"><p>J&#8217;ai dernièrement eu besoin de convertir un petit script ruby en daemon.</p>

<p>J&#8217;utilise dans mes déploiements monitrc pour le monitoring de mes
scripts. Monit check un pidfile pour voir si le processus est actif ou
pas.</p>

<p>J&#8217;ai donc cherché en Ruby quel était la meilleure solution pour que mon
script soit un daemon et puisse générer lui-même son pidfile.</p>

<p>Le projet le plus connu est <a href="http://daemons.rubyforge.org/">daemons</a>.
J&#8217;ai déjà essayé de l&#8217;utiliser, mais je n&#8217;en ai jamais été un grand
convaincu. Je l&#8217;ai toujours trouvé compliqué. Il ne gére pas la
génération de pidfile. Il faut donc pratiquement tout gérer soit même.</p>

<p>Le deuxième projet le plus connu est une sur-couche de daemons c&#8217;est
<a href="https://github.com/kennethkalmer/daemon-kit">daemon-kit</a>. J&#8217;avais déjà
tenté de l&#8217;utiliser, mais je le trouve vraiment trop rigide pour un
simple script. C&#8217;est selon moi plus une massue qu&#8217;autre chose pour créer
un daemon.</p>

<p>C&#8217;est alors que je me suis rappelé avoir entendu parlé d&#8217;un nouveau gem
pour créer des daemons. J&#8217;ai cherché et j&#8217;ai ainsi pu découvrir
<a href="https://github.com/bazaarlabs/dante">dante</a>. Ce projet est exactement
ce que je cherchais. Il est simple et fait le boulot de créer un daemon.</p>

<p>Par défaut, il supporte quelques arguments à passer en ligne de
commande. Ces arguments font l&#8217;essentiel du travail d&#8217;un daemon.</p>

<p>Voici une liste des arguments par défaut disponible.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>-p, --port PORT Specify port
</span><span class='line'> (default: )
</span><span class='line'>-P, --pid FILE save PID in FILE when using -d option.
</span><span class='line'> (default: /var/run/scheduler.pid)
</span><span class='line'>-d, --daemon Daemonize mode
</span><span class='line'>-l, --log FILE Logfile for output
</span><span class='line'>-k, --kill [PORT] Kill specified running daemons - leave
</span><span class='line'>blank to kill all.
</span><span class='line'>-u, --user USER User to run as
</span><span class='line'>-G, --group GROUP Group to run as
</span><span class='line'>-?, --help Display this usage information.</span></code></pre></td></tr></table></div></figure>


<p>On peux ainsi définir, le PID, le fichier de log, l&#8217;utilisateur et le
group lançant le daemon ( si lancé en root ). Seul petit argument qui ne
me semble pas essentiel, c&#8217;est l&#8217;argument du port. Mais l&#8217;usage initial
de dante est de lancé des applications rack. Voila pourquoi on
retrouve cet argument.</p>

<p>Une de ses autre fonctionnalités intéressantes est tout simplement le
fait que l&#8217;on peux ajouter des options. Il peux donc aussi servir de
gestion d&#8217;option pour son application.</p>

<p>Pour l&#8217;utiliser rien de plus simple. Il suffit de mettre votre script
dans un block <code>Dante.run</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Dante</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s1">&#39;myapp&#39;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">opts</span><span class="o">|</span>
</span><span class='line'> <span class="n">myapp</span><span class="o">.</span><span class="n">run</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Je suis vraiment impressionné par ce gem qui est issu de la société
<a href="http://gomiso.com">gomiso</a>. Merci à elle de nous permettre d&#8217;avoir
d&#8217;aussi bon gem.</p>

<p><a href="http://blog-en.shingara.fr/dante-lets-you-put-some-daemon-in-your-code.html">English Translation</a></p>
</div>
  
  


    </article>
  
  
    <article>
      
  <header>
    
      <h1 class="entry-title"><a href="/moped-le-nouveau-driver-mongodb-pour-ruby.html">moped le nouveau driver mongodb pour ruby</a></h1>
    
    
      <p class="meta">
        








  


<time datetime="2012-04-30T09:42:00+02:00" pubdate data-updated="true">Apr 30<span>th</span>, 2012</time>
        
         | <a href="/moped-le-nouveau-driver-mongodb-pour-ruby.html#disqus_thread">Comments</a>
        
      </p>
    
  </header>


  <div class="entry-content"><p>Depuis décembre 2011, <a href="https://github.com/bernerdschaefer">Bernerd Schaefer</a> a commencé a créer un
driver MongoDB pour ruby. Ce nouveau driver MongoDB n&#8217;a pas été crée par
10Gen (créateur de MongoDB) contrairement au gem
<a href="https://github.com/mongodb/mongo-ruby-driver">mongo-ruby-driver</a>.</p>

<h1>Le but de ce gem</h1>

<p>Ce gem a été crée suite aux frustrations de l&#8217;équipe de développement de
Mongoid qui a fait plusieurs fois des propositions de changement de
design du driver officiel. Tous changement de design du driver a été
refusé.</p>

<h2>Thread-safe</h2>

<p>Un des buts de ce gem est de permettre d&#8217;avoir un gem qui est le plus
possible thread-safe. Le driver officiel mongoDB est parfois considéré
comme non thread-safe notament par <a href="https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting">Mike Perham</a>.
C&#8217;est un vrai problème alors que la communauté ruby
commence enfin à redécouvrir les threads. Cet état empêche par exemple
l&#8217;usage de <a href="http://mperham.github.com/sidekiq/">sidekiq</a> avec MongoDB.</p>

<h2>Suppression de l&#8217;extension</h2>

<p>Avec le driver MongoDB officiel, il est très fortement conseillé
d&#8217;installer le gem <a href="http://rubygems.org/gems/bson_ext">bson_ext</a> sans
celui-ci les performances sont beaucoup moins bonnes. Par contre cette
extension étant écrite en C, elle est incompatible avec JRuby. Il a
fallu créer une version JRuby du gem bson. Ça rend la maintenabilité
plus complexe.</p>

<p>Dans le cas de moped, aucune extension C n&#8217;est à prévoir.
Il est naturellement plus performant. Il arriverait même à être plus
performant que l&#8217;extension C selon
les benchmarks réalisés pour le projet.</p>

<p>Seul ombre au tableau, la génération d&#8217;un ObjectId est plus lente avec
moped qu&#8217;avec le gem officiel bson selon un <a href="https://groups.google.com/d/topic/mongoid/87IdIKO8-VM/discussion">thread de la mailing-list de Mongoid</a>.
Mais cela pourra être améliorer par la suite, je n&#8217;en doute pas.</p>

<h2>Une API plus simple</h2>

<p>L&#8217;API de moped est vraiment plus belle que celle du gem mongo. Ce
changement est bien sûr subjectif. Elle est beaucoup plus orienté ruby.
Elle permet aussi la combinaison de recherche/mise à jour.</p>

<h2>Meilleure gestion du replicat Set</h2>

<p>Une des fonctionnalités principale de MongoDB est la gestion du
replicatSet. Avec Moped, cette gestion devient vraiment plus souple et
surtout ne lève plus d&#8217;exception la première fois que le node maître est
down. Cette fois ci le basculement se fait automatiquement.</p>

<p>Plus besoin de passer la liste de vos nodes en configuration. Moped
utilise directement les mécanismes de MongoDB pour découvrir les
nouveaux nodes et ainsi les utiliser.</p>

<h1>Les limitations</h1>

<p>Par contre, moped a certaine limitation.</p>

<h2>Ruby 1.9 uniquement</h2>

<p>Moped n&#8217;est pas compatible avec Ruby &lt; 1.9. Le choix de l&#8217;implémentation
a été fait de ne pas être compatible avec les plus anciennes version de
ruby.</p>

<p>Personnellement, je suis d&#8217;accord avec ce choix, car l&#8217;usage de ruby 1.8
doit disparaitre.</p>

<h2>Pas de support de GridFS</h2>

<p>GridFS n&#8217;est pas supporté nativement dans moped. Ce choix a été fait
pour limiter le core du gem. Bien sûr rien n&#8217;empêche de créer une
extension de moped gérant GridFS.</p>

<h1>Intégration dans Mongoid 3</h1>

<p>Mongoid 3.x utilisera désormais moped à la place du driver mongodb de
10Gen. Si vous souhaitez donc commencer un peu à l&#8217;utiliser essayer
cette nouvelle version majeur de Mongoid.</p>

<p>Attention, Mongoid 3 n&#8217;est actuellement pas release. Si vous souhaitez
l&#8217;utiliser il faudra utiliser la branche master de Mongoid. Le
dévelopment y est toujours actif.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">gem</span> <span class="s1">&#39;mongoid&#39;</span><span class="p">,</span> <span class="ss">:git</span> <span class="o">=&gt;</span> <span class="s1">&#39;git://github.com/mongoid/mongoid&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p><a href="http://blog-en.shingara.fr/moped-the-new-mongodb-ruby-driver.html">English Translation</a></p>
</div>
  
  


    </article>
  
  
    <article>
      
  <header>
    
      <h1 class="entry-title"><a href="/quiet-assets-le-limiteur-de-log.html">Quiet Assets le gem qui limite les logs</a></h1>
    
    
      <p class="meta">
        








  


<time datetime="2012-04-25T09:42:00+02:00" pubdate data-updated="true">Apr 25<span>th</span>, 2012</time>
        
         | <a href="/quiet-assets-le-limiteur-de-log.html#disqus_thread">Comments</a>
        
      </p>
    
  </header>


  <div class="entry-content"><p>Voici une semaine, j&#8217;ai découvert un gem vraiment pratique.
<a href="https://github.com/evrone/quiet_assets">quiet_assets</a>.</p>

<p>Ce gems ne fait pas grand chose, mais a de grand avantage quand on
développe une application Rails (> 3.1) avec des assets en utilisant la
technologie &#8216;asset_pipeline&#8217;.</p>

<p>Si c&#8217;est votre cas, vous vous êtes déjà rendu compte que chaques requêtes faites
à votre application pour obtenir vos assets est logués dans votre
fichier de log ( development.log en environement de dévelopment ). Des
requêtes comme celle-ci :</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>Started GET "/assets/application.js?body=1" for 127.0.0.1 at 2012-02-13 13:24:04 +0400
</span><span class='line'>Served asset /application.js - 304 Not Modified (8ms)</span></code></pre></td></tr></table></div></figure>


<p>On se retrouve ainsi à devoir remonter dans son fichier de logs pour
obtenir les logs qui nous interresse vraiment ( les log de la requête
courante ). Notre fichier de log est
vraiment pollué par ces assets si vous en avez comme moi beaucoup.</p>

<p>C&#8217;est là que <a href="https://github.com/evrone/quiet_assets">quiet_assets</a>
devient vraiment interressant et pratique. Vous ajoutez ce gem dans
votre Gemfile au niveau du groupe &#8216;development&#8217; et tous vos logs d&#8217;assets
disparaissent. Ils ne sont tous simplement plus logguées dans votre fichier
de log. On retrouve ainsi un fichier de log rapide a consulter et moins
pollué par des informations inutiles.</p>

<p>Comme quoi de tout petits gems peuvent nous rendre de grand service.</p>

<p><em>Edit du 27 Avril 2012</em></p>

<p>On pourrait se dire que cela pourrait être directement integré à Rails.
Hélas cela à été fait en partie, mais pas complétement.</p>

<p>Depuis la version 3.2.x et l&#8217;<a href="https://github.com/rails/rails/issues/2639">issue 2639</a>
nous pouvons configurer le logger de Sprockets. Mais il n&#8217;est pas seul à
afficher les informations. Actionpack log toujours les requêtes faites
pour obtenir ces assets. Vous ne pourrez donc pas avoir un fichier de
log complétement épuré.</p>

<p><a href="http://blog-en.shingara.fr/quiet-assets-help-you-to-have-little-log.html">English translation</a></p>
</div>
  
  


    </article>
  
  
    <article>
      
  <header>
    
      <h1 class="entry-title"><a href="/telecharger-fichier-de-basecamp.html">Récupération de ses fichiers sur basecamp</a></h1>
    
    
      <p class="meta">
        








  


<time datetime="2012-04-20T09:38:00+02:00" pubdate data-updated="true">Apr 20<span>th</span>, 2012</time>
        
         | <a href="/telecharger-fichier-de-basecamp.html#disqus_thread">Comments</a>
        
      </p>
    
  </header>


  <div class="entry-content"><p>Au niveau de mon travail actuel chez <a href="http://bemyboat.com">Be My Boat</a>,
nous sommes actuellement en train de migrer de
<a href="http://basecamphq.com">Basecamp</a> vers
<a href="http://trello.com">Trello</a>.</p>

<p>Pour éviter de perdre toutes les informations qui ont été mis dans
basecamp, nous avons réalisé un import complet. Par contre, l&#8217;import ne
comprend pas les fichiers qui ont pu être ajouté dans basecamp.</p>

<p>Pour ne pas perdre ces fichiers qui font parti du patrimoine de
l&#8217;entreprise, j&#8217;ai créé un petit script pour télécharger tous ces
fichiers.</p>

<p>Je vous le partage si vous en avez besoin un jour.</p>

<div><script src='https://gist.github.com/2420838.js?file='></script>
<noscript><pre><code>require 'faraday'
require 'faraday_middleware'

url_project = 'https://ciblonet.basecamphq.com'
project_id = 3684800
user_name = 'shingara'
password = 'xxxx'

class Attachment

  def initialize(conn, attachment)
    @conn = conn
    @attachment = attachment
  end

  def collection
    @attachment['collection'].to_s
  end

  def dir
    Dir.mkdir(collection) unless Dir.exists?(collection)
    collection
  end

  def fetch
    File.new(File.join(dir, @attachment['name']), 'w').write(@conn.get(@attachment['download_url']).body)
  end
end

class Attachments
  def initialize(conn, project_id, step=nil)
    @conn = conn
    @project_id = project_id
    @attachments_index = 100
    @step = step
  end

  def url
    if @step
      &quot;/projects/#{@project_id}/attachments.xml?n=#{@step}&quot;
    else
      &quot;/projects/#{@project_id}/attachments.xml&quot;
    end
  end

  def entries
    @entries ||= @conn.get(url) do |req|
      req.headers['Accept'] = 'application/xml'
      req.headers['Content-Type'] = 'application/xml'
    end.body['attachments']
  end

  def fetch
    entries.each do |attachment|
      Attachment.new(@conn, attachment).fetch
    end
  end

  def more?
    entries.size &gt; 99
  end
end


class FetchAttachments

  def self.execute(conn, project_id)
    a = Attachments.new(conn, project_id)
    a.fetch
    step = 100
    while a.more?
      a = Attachments.new(conn, project_id, step)
      a.fetch
      step += 100
    end
  end
end

con = Faraday.new(:url =&gt; url_project) do |builder|
  builder.use Faraday::Request::BasicAuthentication, user_name, password
  builder.use Faraday::Response::Logger
  builder.response :xml, :content_type =&gt; /\bxml$/
  builder.use Faraday::Adapter::NetHttp
end

FetchAttachments.execute(con, project_id)
</code></pre></noscript></div>


<p>Dans ce script j&#8217;utilise
<a href="https://github.com/technoweenie/faraday">Faraday</a> pour faire le requêtage avec l&#8217;API et
aussi télécharger les fichiers. Je suis personnellement un grand fan de
Faraday. C&#8217;est selon moi la meilleure librairie de requêtage HTTP
actuelle du monde Ruby. Utilisez la dès que vous avez besoin de faire du
requêtage HTTP.</p>
</div>
  
  


    </article>
  
  
    <article>
      
  <header>
    
      <h1 class="entry-title"><a href="/translate-on-mongoid.html">Localize avec mongoid</a></h1>
    
    
      <p class="meta">
        








  


<time datetime="2012-02-06T22:02:00+01:00" pubdate data-updated="true">Feb 6<span>th</span>, 2012</time>
        
         | <a href="/translate-on-mongoid.html#disqus_thread">Comments</a>
        
      </p>
    
  </header>


  <div class="entry-content"><p>Depuis la version 2.4.0 de <a href="http://mongoid.org">Mongoid</a>, une nouvelle
fonctionnalité à été ajoutée très discrétement. C&#8217;est tout simplement la
gestion native des traductions en base.</p>

<p>La <a href="http://mongoid.org/docs/documents/localized.html">documentation compléte</a> de cette fonctionnalité est sur le site de
<a href="http://mongoid.org">mongoid</a>.</p>

<p>Grâce à cette fonctionnalité, on peut définir tout simplement qu&#8217;un
champs de Mongoid est localizable. La gestion de la locale est faite de
manière très intelligente et surtout en complète coordination avec
MongoDB.</p>

<p>Contrairement à une gestion de traduction dans une Base de donnée
relationnelle, qui créé une table de liaison, Mongoid stocke un hash
avec la locale comme clé et la traduction comme valeur.</p>

<p>Mongoid n&#8217;a plus qu&#8217;à faire la glue entre le système pour que les accès
en lecture/écriture en fonction de la locale et la recherche</p>
</div>
  
  


    </article>
  
  
    <article>
      
  <header>
    
      <h1 class="entry-title"><a href="/mailtrap-l-aide-au-staging.html">Mailtrap l&#8217;aide au staging</a></h1>
    
    
      <p class="meta">
        








  


<time datetime="2012-01-24T22:17:00+01:00" pubdate data-updated="true">Jan 24<span>th</span>, 2012</time>
        
         | <a href="/mailtrap-l-aide-au-staging.html#disqus_thread">Comments</a>
        
      </p>
    
  </header>


  <div class="entry-content"><p>Avant chaque mise en production d&#8217;un projet, il faut le test dans un
environement de staging. Pour avoir un environement le plus proche de
notre environement de production, une pratique courante est d&#8217;éffectuer
un dump de la base de production pour avoir un jeu de donnée complet et
valide. Ça nous permet aussi de vérifier que nos migrations ne posent
pas de problème, tester quelques pages au niveau de leur performance.</p>

<p>En gros faire plein de test comme si on jouait avec la prod mais sans
toucher au donnée de production.</p>

<p>Le plus gros soucis que l&#8217;on rencontre et beaucoup d&#8217;entre nous l&#8217;ont
rencontré, c&#8217;est l&#8217;envoi d&#8217;email. Tous les emails copié de la production
sont valide et posséde un utilisateur au bout. Si nous envoyons un email
réellement cela peut vite être problèmatique. Les solutions utilisées
généralement sont les suivantes.</p>

<h2>Remplacement de tous les emails de la base de donnée.</h2>

<p>Une pratique simple est courant est la tâche qui remplace tous les
emails de la base de donnée par des emails possédés par la société.
Cette technique marche parfaitement, mais pose quelques problèmes :</p>

<ul>
<li>Il faut penser a toujours faire la modification après chaque copie de
la base de production.</li>
<li>Il faut mettre à jour son script pour remplacer tous les nouveaux
champs qui posséde des emails si on en ajoute</li>
<li>Il devient difficile de savoir à qui était réelement destiné l&#8217;email
initial. On peux ainsi passer à coté de quelques bugs.</li>
</ul>


<h2>Ne plus contacter de serveur SMTP et créer un fichier par email</h2>

<p>Avec le framework Ruby on Rails, il est possible de définir que tous les
emails envoyés sont mis dans un fichier plutôt qu&#8217;envoyer par SMTP. Il
suffit de définir un nouveau smtp_delivery</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">ActionMailer</span><span class="o">::</span><span class="no">Base</span><span class="o">.</span><span class="n">delivery_methods</span> <span class="o">=</span> <span class="ss">:file</span>
</span></code></pre></td></tr></table></div></figure>


<p>Cette technique permet d&#8217;être sûr qu&#8217;aucun email n&#8217;est envoyé au client
finaux. L&#8217;inconvénient de cette technique est le stockage et la lecture
des emails. Tous les emails sont stocké sous forme de fichier
directement sur le serveur. Il peux donc être fastidieux de connaitre
les nouveaux emails envoyés, car ils sont classé par destinataire. On
peux ainsi ne pas constater qu&#8217;un email est envoyé sous certaine
conditions. De même, si votre application est utilisé par des personnes
n&#8217;ayant pas un accès shell à votre serveur, ils ne pourront pas lire les
mails envoyés.</p>

<h2>Le mock SMTP</h2>

<p>Cette technique est selon moi la meilleure actuellement. Elle consiste
tout simplement à emuler un vrai serveur SMTP. Par contre, ce serveur ne
transmet pas les emails qu&#8217;il reçoit. Il les stocke et vous permet de
les consulter dans un client mail classique. Ils sont conservé
entièrement.</p>

<p>L&#8217;avantage est que n&#8217;importe qui peux consulter les emails générés, sans
aucune connaissance technique évolués et ils sont conservé entièrement.</p>

<p>A ma connaissance, il existe 3 produits qui permettent cela.</p>

<ul>
<li><a href="http://mailcatcher.me/">Mailcatcher</a></li>
<li><a href="http://mailtrap.io/">Mailtrap.io</a></li>
<li><a href="http://mocksmtpapp.com/">MockSMTP.app</a></li>
</ul>


<h3>Mailcatcher</h3>

<p>C&#8217;est un produit open source tres simple d&#8217;utilisation. Vous télécharger
le gem, vous lancer la commande <code>mailcatcher</code> et c&#8217;est fini. Vous avez
ainsi un serveur SMTP sur le port 1025 et un client mail sur le port
1080.</p>

<p>Je vous le conseille dans un environement de développement. Il a en plus
quelques petits addons comme la notification growl.</p>

<p>Le seul soucis que j&#8217;ai rencontré avec est le deployement dans un
environement de staging. la commande <code>mailcatcher</code> ne permet pas
d&#8217;écouter sur toutes les interfaces. Il faut donc mettre un proxy devant
pour le rendre accessible à tout le monde. On doit donc le maintenir et
le gérer. Cela peux être un peu compliqué juste pour un simple mock.
Bien sûr rien ne vous empêche de le faire.</p>

<h3>Mailtrap.io</h3>

<p>Voici un projet que j&#8217;ai découvert que très récement. Le concept est
exactement le même que celui de mailcatcher, sauf que vous n&#8217;avez plus à
gérer l&#8217;hébergement vous même. Tout est géré par
<a href="http://railsware.com/">railsware</a>, l&#8217;éditeur de ce service.</p>

<p>Vous créer un compte sur leur site, vous créer un serveur SMTP fictif et
c&#8217;est fini.</p>

<p>Vous obtenez les informations de connection à ce SMTP. Une fois que vous
définissez ces paramètres dans votre application, tous les emails seront
envoyé directement à Mailtrap.</p>

<p>Une gestion de collaboration sur les mailbox vous permet d&#8217;ajouter vos
collaborateur à cette mailbox pour qu&#8217;ils puissent voir les emails.</p>

<p>Cette solution est vraiment simple a mettre en oeuvre et très pratique.
Petit plus, c&#8217;est encore gratuit actuellement. Donc profitez en.</p>
</div>
  
  


    </article>
  
  
    <article>
      
  <header>
    
      <h1 class="entry-title"><a href="/une-journee-dediee-i-mongodb.html">Une journée dédiée à MongoDB</a></h1>
    
    
      <p class="meta">
        








  


<time datetime="2010-05-19T00:00:00+02:00" pubdate data-updated="true">May 19<span>th</span>, 2010</time>
        
         | <a href="/une-journee-dediee-i-mongodb.html#disqus_thread">Comments</a>
        
      </p>
    
  </header>


  <div class="entry-content"><p><img src="http://blog.shingara.fr/files/badge-mongofr-large.png" alt="mongoFR badges"/></p>

<p>Le 21 Juin se tiendra à Paris un événement auquel je vous invite à venir. Cet événement sera dédié à <a href="http://mongodb.com">MongoDB</a>, le <a href="http://www.10gen.com/conferences/event_mongofr_21june10">MongoFR</a>.</p>

<p>J&#8217;ai la chance de pouvoir proposer une petite conférence sur un retour d&#8217;expérience : ma migration de SQL à MongoDB sur <a href="http://oupsnow.rubyforge.org">Oupsnow</a>.
Hormis les développeurs de <a href="http://10gen.com">10Gen</a>, il n&#8217;y aura que des Rubyists.</p>

<p>Selon moi, cette nouvelle technologie qu&#8217;est MongoDB est assez prometteuse.</p>

<p>Pour découvrir MongoDB, venez nombreux <a href="http://www.10gen.com/conferences/event_mongofr_21june10">le 21 Juin</a> !</p>

<p><a href="http://blog-en.shingara.fr/one-day-dedicated-to-mongodb.html">English translation</a></p>
</div>
  
  


    </article>
  
  <div class="pagination">
    
      <a class="prev" href="/blog/page/2/">&larr; Older</a>
    
    <a href="/blog/archives">Blog Archives</a>
    
  </div>
</div>
<aside class="sidebar">
  
    <section>
  <h1>Recent Posts</h1>
  <ul id="recent_posts">
    
      <li class="post">
        <a href="/pourquoi-jai-arrete-decent-exposure.html">pourquoi j&#8217;ai arrêté decent_exposure</a>
      </li>
    
      <li class="post">
        <a href="/tester-ses-vues-rabl.html">tester ses vues rabl</a>
      </li>
    
      <li class="post">
        <a href="/vundle-ou-le-bundler-de-vim.html">vundle ou le bundler de vim</a>
      </li>
    
      <li class="post">
        <a href="/dante-pour-mettre-du-daemon-dans-son-code.html">dante pour mettre du daemon dans son code</a>
      </li>
    
      <li class="post">
        <a href="/moped-le-nouveau-driver-mongodb-pour-ruby.html">moped le nouveau driver mongodb pour ruby</a>
      </li>
    
      <li class="post">
        <a href="/quiet-assets-le-limiteur-de-log.html">Quiet Assets le gem qui limite les logs</a>
      </li>
    
      <li class="post">
        <a href="/telecharger-fichier-de-basecamp.html">Récupération de ses fichiers sur basecamp</a>
      </li>
    
      <li class="post">
        <a href="/translate-on-mongoid.html">Localize avec mongoid</a>
      </li>
    
      <li class="post">
        <a href="/mailtrap-l-aide-au-staging.html">Mailtrap l&#8217;aide au staging</a>
      </li>
    
      <li class="post">
        <a href="/une-journee-dediee-i-mongodb.html">Une journée dédiée à MongoDB</a>
      </li>
    
  </ul>
</section>

<section>
  <h1>GitHub Repos</h1>
  <ul id="gh_repos">
    <li class="loading">Status updating&#8230;</li>
  </ul>
  
  <a href="https://github.com/shingara">@shingara</a> on GitHub
  
  <script type="text/javascript">
    $.domReady(function(){
        if (!window.jXHR){
            var jxhr = document.createElement('script');
            jxhr.type = 'text/javascript';
            jxhr.src = '/javascripts/libs/jXHR.js';
            var s = document.getElementsByTagName('script')[0];
            s.parentNode.insertBefore(jxhr, s);
        }

        github.showRepos({
            user: 'shingara',
            count: 10,
            skip_forks: false,
            target: '#gh_repos'
        });
    });
  </script>
  <script src="/javascripts/github.js" type="text/javascript"> </script>
</section>


<section>
  <h1>Latest Tweets</h1>
  <ul id="tweets">
    <li class="loading">Status updating&#8230;</li>
  </ul>
  <script type="text/javascript">
    $.domReady(function(){
      getTwitterFeed("shingara", 4, false);
    });
  </script>
  <script src="/javascripts/twitter.js" type="text/javascript"> </script>
  
    <a href="http://twitter.com/shingara" class="twitter-follow-button" data-show-count="true">Follow @shingara</a>
  
</section>


  
</aside>

    </div>
  </div>
  <footer role="contentinfo"><p>
  Copyright &copy; 2012 - Cyril Mougel -
  <span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>

</footer>
  

<script type="text/javascript">
      var disqus_shortname = 'shinydevblog';
      
        
        var disqus_script = 'count.js';
      
    (function () {
      var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
      dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
      (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    }());
</script>



<div id="fb-root"></div>
<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) {return;}
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/all.js#appId=212934732101925&xfbml=1";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>



  <script type="text/javascript">
    (function() {
      var script = document.createElement('script'); script.type = 'text/javascript'; script.async = true;
      script.src = 'https://apis.google.com/js/plusone.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(script, s);
    })();
  </script>



  <script type="text/javascript">
    (function(){
      var twitterWidgets = document.createElement('script');
      twitterWidgets.type = 'text/javascript';
      twitterWidgets.async = true;
      twitterWidgets.src = 'http://platform.twitter.com/widgets.js';
      document.getElementsByTagName('head')[0].appendChild(twitterWidgets);
    })();
  </script>





</body>
</html>
Something went wrong with that request. Please try again.