<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
	xmlns:media="http://search.yahoo.com/mrss/"
>

<channel>
	<title>Jul's blog</title>
	<atom:link href="http://blog.js.hu/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.js.hu</link>
	<description>Musings from the news of web, roleplaying and technology</description>
	<lastBuildDate>Thu, 28 Jul 2011 22:40:32 +0000</lastBuildDate>
	<language>hu</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
	<copyright>2006-2008 </copyright>
	<managingEditor>js@iksz.hu (Jul's blog)</managingEditor>
	<webMaster>js@iksz.hu (Jul's blog)</webMaster>
	<ttl>1440</ttl>
	<image>
		<url>http://blog.js.hu/wp-content/plugins/podpress/images/powered_by_podpress.jpg</url>
		<title>Jul's blog</title>
		<link>http://blog.js.hu</link>
		<width>144</width>
		<height>144</height>
	</image>
	<itunes:subtitle></itunes:subtitle>
	<itunes:summary>A web, a szerepjáték és a technika újdonságaiból, érdekességeiből</itunes:summary>
	<itunes:keywords></itunes:keywords>
	<itunes:category text="Society &#38; Culture" />
	<itunes:author>Jul's blog</itunes:author>
	<itunes:owner>
		<itunes:name>Jul's blog</itunes:name>
		<itunes:email>js@iksz.hu</itunes:email>
	</itunes:owner>
	<itunes:block>no</itunes:block>
	<itunes:explicit>no</itunes:explicit>
	<itunes:image href="http://blog.js.hu/wp-content/plugins/podpress/images/powered_by_podpress_large.jpg" />
		<item>
		<title>Oplog divergence madness</title>
		<link>http://blog.js.hu/2011/07/28/oplog-divergence-madness/</link>
		<comments>http://blog.js.hu/2011/07/28/oplog-divergence-madness/#comments</comments>
		<pubDate>Thu, 28 Jul 2011 22:40:32 +0000</pubDate>
		<dc:creator>js</dc:creator>
				<category><![CDATA[Céges kultúra]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[clearcase]]></category>
		<category><![CDATA[multisite]]></category>
		<category><![CDATA[oplog divergence]]></category>
		<category><![CDATA[restorereplica]]></category>

		<guid isPermaLink="false">http://blog.js.hu/?p=211</guid>
		<description><![CDATA[I never thought I&#8217;ll ever blog about ClearCase, but I have to write about the latest issue I had. One of the sites I maintain has a couple of VOBs (Versioned Object Base, it&#8217;s called repository in other version control systems) &#8230; <a href="http://blog.js.hu/2011/07/28/oplog-divergence-madness/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I never thought I&#8217;ll ever blog about ClearCase, but I have to write about the latest issue I had.</p>
<p>One of the sites I maintain has a couple of VOBs (Versioned Object Base, it&#8217;s called repository in other version control systems) which got corrupted. Someone from NAS team (it&#8217;s not your home NAS system) tweaked with NFS parameters, and locked out the VOB server for a couple of seconds. It&#8217;s not nice.</p>
<p>Anyways, the server reboots every now and then, to add more spice.<span id="more-211"></span></p>
<p><span class="Apple-style-span" style="color: #444444; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px;"><a style="color: #ff4b33;" href="http://blog.js.hu/wp-content/uploads/Cigar.jpg"><img class="alignright size-full wp-image-212" style="border-style: initial; border-color: initial;" title="Cigar" src="http://blog.js.hu/wp-content/uploads/Cigar.jpg" alt="&quot;At the eight day, God said: I need a drink.&quot; Now I need it." width="400" height="464" /></a></span></p>
<p>To serve users better, I got the problem report two days later (a problem report in normal severity should be fixed in 5 business days). You know, you have to fight with Level 1, then comes Level 2 where they think they can solve the issue by putting them aside.</p>
<p>Fortunately, I keep a week-long nightly snapshots around, and I was able to restore damaged vobs. I had no issues with the first one, but the second vob had local changes since the last good backup.</p>
<p style="padding-left: 30px;">Let me digress a bit to tell you how ClearCase keeps replicated data up to date between nodes.</p>
<p style="padding-left: 30px;">First off, the core principle is quite simple: you can write your changes, but you can only read others&#8217; changes. It goes down to ClearCase&#8217;s core change principle: you have to check out files you want to modify, and it makes read-only for others.</p>
<p style="padding-left: 30px;">How you can support multiple users then? The answer is branching. Everybody creates his/her own topic branch, which then will get merged back to baseline. To broaden the solution back to multisite usage, every version, branch, label is mastered by a replica, where it can be written or modified. This simple principle is the core of base ClearCase, which then causes trouble in various places.</p>
<p style="padding-left: 30px;">OK, we have a couple of replicas, now update them. For this, the vob maintains a log of operations (a.k.a. oplog) for every replica. The local replica keeps its oplog tidy, but it also stores all the other replicas&#8217; oplogs, in case we have to update a replica with another&#8217;s changes. Yes, you can create your own update topology.</p>
<p style="padding-left: 30px;">To make things more quirky, the local replica keeps track of oplog counter (also called epoch number) of what it <strong>thinks</strong> other replicas have. This is how a replica can update a replica with another one&#8217;s changes.</p>
<p style="padding-left: 30px;">So far it&#8217;s easy to follow, but here comes the problem: when a replica updates another, it <strong>assumes</strong> the update will be imported, and it increases the appropriate counters, no matter the packets reached destination. This fragile system causes the most common problem with ClearCase: synchronization issues.</p>
<p style="padding-left: 30px;">You can fight them with updating your copy of a remote replica&#8217;s epoch list, by manually updating it, or by using restorepackets. In the latest version, you can even have a diagnostic tool which shows you what command should be run on the other replica. These methods don&#8217;t solve the problem once and all, but they give job security for a ClearCase admin.</p>
<p> Now I can be a bit more technical: the second vob&#8217;s epoch number was higher than the restored version&#8217;s. This means we have to switch to restorereplica mode, where we ask others to give our changes back. Fortunately ClearCase has an admin guide which describes what to do in a situation like this. Integrity check of the database (where relations are stored), vob source pool check (where file differences are stored), fix all issues, and then switch to restorereplica, and wait for the updates from all other replicas.</p>
<p>Nice. Source pool checking pointed to 6 containers being missing. Sure enough all of them were in place. Nevermind, I fixed them, and then checkvob returned with no errors. Let&#8217;s jump right into restorereplica!</p>
<p>I started with France. Packets back and forth, looks right&#8230; or not? Importing says there is still a missing container.</p>
<p>At this point the server crashed, and got rebooted.</p>
<p>I started all the tests over. Database check went well, but checkvob showed 6 missing containers <strong>again</strong>, but now with really missing files. Oh my. Switch back from normal mode, fix the holes, turn on restorereplica again, then send out updates to replicas. Done.</p>
<p>I started with France again. Packets back and forth. Now there&#8217;s another issue in importing: the source container I just restored has some versions which are not in the database.</p>
<p>How can I remove a version from a source container?</p>
<p>It turned out the format is not too difficult. A line starts with caret (^) is a command. We have a couple of commands:</p>
<ul>
<li>^E: element, it tells you the element&#8217;s UUID</li>
<li>^V: version. After version&#8217;s UUID, it contains the branch number (in hex), and version number (hex).</li>
<li>^B: branch. Branch UUID, branch number, and some other data.</li>
<li>^I: insert lines in a version. Branch number, version number, and number of lines. Then, the actual lines.</li>
<li>^D: delete lines from a version. Branch number, version number, and the number of lines to be deleted.</li>
</ul>
<p>It has some other commands as well, but they&#8217;re not important if you want to hack a container.</p>
<p>I solved all my restoring needs, but this hack was the tip of the iceberg.</p>
<p>And it happened, soon enough. All packet import says there&#8217;s an oplog divergence: the replica thinks the change was in a different oplog entry. Now every replica is stuck, no one can update any other.</p>
<p>Now you can either call IBM, or you put an axe on the table.</p>
<p>After a long meeting we decided option two will be the solution. We had more than 1000 changes in a replica, which should be sent to other sites, and we don&#8217;t have weeks to figure out which bit went to the wrong place.</p>
<p>When you have a divergence, the easiest way is to get rid of the whole oplog. Just choose a replica which will survive, remove other replicas one by one, and when the last remote replica gets removed, your vob will return to it&#8217;s original state. No oplogs, no export_sync records (it is a way to reset a replica&#8217;s epoch matrix, but may I ask why we have two different methods for this?), no mastership.</p>
<p>To do this, all you have to do is to make other replicas obsolete, and then remove them at the selected site.</p>
<p>Yes, sure.</p>
<p>At this point I learned a vob database&#8217;s journal can hold at most 2GB transaction data, and sometimes it&#8217;s not enough to remove the last replica. Why? Because of the enormous amount of oplogs and export_sync records.</p>
<p>Sadly it never told me. It just hung. After a couple of hours I got suspicious. I&#8217;ve listened into all the processes in question with truss, but all of them were just sleeping. Aha, deadlock. Also cleaning up corrupted transaction file droppings, which was all described in a technote.</p>
<p>At this point I felt 2.7GB for a database is a bit too much. I dumped then loaded the database, and it reduced to under 1GB. Well, ten years is a long time to fragment a database.</p>
<p>Here comes another fancy feature of ClearCase: from time to time a lot of unnecessary data gets collected. Nobody really cares about who and when locked the vob (we have to lock the database every day during backup), or who applied labels. To remove these data we have a vob_scrubber utility, which weeds our garden.</p>
<p>Oplogs are kept forever. Export sync records kept forever. I changed the rules to keep only 7 days, but scrubber failed miserably.</p>
<p>In a technote I never seen before I found the solution: peel off oplogs and export sync records. Start with 120 days, then go on to 90, 60, and 30 days. Then finish off with a 7 days amount of export sync records being kept, and then, you&#8217;ll be able to remove the latest replica.</p>
<p>Now I&#8217;m at this point, but another 9 hours passed, and I need a cigar.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.js.hu/2011/07/28/oplog-divergence-madness/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Vendoring gems with style</title>
		<link>http://blog.js.hu/2011/05/18/vendoring-gems-with-style/</link>
		<comments>http://blog.js.hu/2011/05/18/vendoring-gems-with-style/#comments</comments>
		<pubDate>Wed, 18 May 2011 15:57:14 +0000</pubDate>
		<dc:creator>js</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[bundler]]></category>
		<category><![CDATA[guard-bundler]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rvm]]></category>
		<category><![CDATA[vendoring gems]]></category>

		<guid isPermaLink="false">http://blog.js.hu/?p=208</guid>
		<description><![CDATA[A couple of months ago Ryan McGeary wrote an article about why @defunkt&#8216;s idea of “Vendor Everything” still applies. I&#8217;m playing with this for a while, and I came up with these best practices. First of all, we need a &#8230; <a href="http://blog.js.hu/2011/05/18/vendoring-gems-with-style/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A couple of months ago Ryan McGeary wrote an article about why <a href="http://twitter.com/defunkt">@defunkt</a>&#8216;s <a href="http://errtheblog.com/posts/50-vendor-everything">idea</a> of <a title="Ryan McGeary: &quot;Vendor Everything&quot; Still Applies" href="http://ryan.mcgeary.org/2011/02/09/vendor-everything-still-applies/">“Vendor Everything” still applies</a>.  I&#8217;m playing with this for a while, and I came up with these best practices.<span id="more-208"></span> First of all, we need a ruby platform (yes, we need rvm):</p>
<pre>$ echo rvm 1.9.2 &gt; .rvmrc
$ rvm rvmrc load</pre>
<p><del>We&#8217;ll going to store project-related binaries in <code>bin</code> folder, why don&#8217;t we add this to the search path? This line is a good candidate of a <code>.bashrc</code> or <code>.zshenv</code> line:</del></p>
<pre><del>$ export PATH="./bin:$PATH"</del></pre>
<p><strong>UPDATE:</strong> I have to admit this is the weakest part of the solution, or, in other words, this is the least elegant way of doing things. However, we use bundler anyways, why don&#8217;t we use it? Thus, open our development console with this command instead:</p>
<pre>$ bundle exec $SHELL</pre>
<p>This command just lets you peek inside the bundle, with gems, <code>PATH</code> settings, and such funny things. Just to the point, and you don&#8217;t have to worry again of malicious binaries in world-writable directories (funny things in <code>/tmp/bin/ls</code> for example).  I have a couple of projects in parallel, why should we store all these gems multiple times?</p>
<pre>$ mkdir ~/.bundle
$ ln -s ~/.bundle vendor/ruby</pre>
<p>Now, we can bundle our stuff:</p>
<pre><del>$ bundle --path vendor --binstubs</del>
$ bundle --path vendor</pre>
<p>(UPDATE: <code>--binstubs</code> is not required since we use <code>bundle exec $SHELL</code>). You have to keep bundled environments out of versioned files:</p>
<pre><del>$ (echo bin/; echo vendor/ruby/) &gt; .gitignore</del>
$ echo vendor/ruby/ &gt; .gitignore</pre>
<p>That&#8217;s it (UPDATE: putting bin/ to .gitignore is unnecessary now).  I found only one issue with this setup: I&#8217;m using guard for a while, and while nearly everything works well, I was not able to get guard-bundler working. Until a recent update.  The only issue was this: guard (just like all the commands living in <code>./bin</code>) runs in bundler&#8217;s environment, however, in order to run <code>bundle</code> command, you actually have to have it installed. However, bundler is not installed inside the bundled environment.  As it turns out the answer is easy, but not intuitive: let&#8217;s install bundler into the bundled environment:</p>
<pre><del>$ bundle exec gem install bundler</del>
$ gem install bundler</pre>
<p>(UPDATE: bundle exec is not needed in development console.)</p>
<p>Now we have the executable inside, which <code>guard-bundler</code> can run in a <code>Bundler::with_clear_env</code> block (which resets environment as it was outside), and it can install gems, flowers, unicorns, double rainbows.  With these settings we get pretty much the same experience as a non-rvm environment, or a dedicated gemset for every project.  Sometimes, when <code>.bundle</code> becomes too big, I just dump it and start over. It doesn&#8217;t take too long anyways.  To wrap up, we achieved the following:</p>
<ol>
<li>We use rvm</li>
<li>However, we got rid of it&#8217;s bundler helpers</li>
<li>We don&#8217;t rely on the bundler pool using executables / scripts</li>
<li>… but we have a pool, and we don&#8217;t have multiple copies the same gems (ssd is still not cheap)</li>
<li>Most shortcomings of vendoring gems are hidden</li>
</ol>
<p>Enjoy.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.js.hu/2011/05/18/vendoring-gems-with-style/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Electronic invoicing in Hungary &#8212; in Hungarian</title>
		<link>http://blog.js.hu/2011/04/17/electronic-invoicing-in-hungary-in-hungarian/</link>
		<comments>http://blog.js.hu/2011/04/17/electronic-invoicing-in-hungary-in-hungarian/#comments</comments>
		<pubDate>Sat, 16 Apr 2011 23:05:02 +0000</pubDate>
		<dc:creator>js</dc:creator>
				<category><![CDATA[Privát]]></category>
		<category><![CDATA[hungarian]]></category>
		<category><![CDATA[invoice]]></category>
		<category><![CDATA[rant]]></category>

		<guid isPermaLink="false">http://blog.js.hu/?p=205</guid>
		<description><![CDATA[Note to my intl readers: sorry for this rant in Hungarian. Látván a remek Harvest, FreshBooks, vagy az európai InvoiceMachine rendszereket bizony elszomorító, hogy Magyarországon miért kellett körbebástyázni ezt a területet egy mikrovállalkozásnak nem betartható szabályokkal, amikhez hasonló más országokban (értsd: &#8230; <a href="http://blog.js.hu/2011/04/17/electronic-invoicing-in-hungary-in-hungarian/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Note to my intl readers: sorry for this rant in Hungarian.</p>
<p><!-- p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px Times} p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px Times; min-height: 19.0px} p.p3 {margin: 0.0px 0.0px 20.0px 10.0px; text-align: center; font: 16.0px Times} p.p4 {margin: 0.0px 0.0px 0.0px 10.0px; text-align: justify; text-indent: 16.0px; font: 13.0px Times} p.p5 {margin: 0.0px 0.0px 0.0px 10.0px; text-align: justify; text-indent: 16.0px; font: 13.0px Times; min-height: 16.0px} p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Times} p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; text-align: justify; font: 13.0px Times; min-height: 16.0px} p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; text-align: justify; font: 14.0px Times} p.p9 {margin: 0.0px 0.0px 0.0px 10.0px; text-align: justify; font: 13.0px Times} p.p10 {margin: 0.0px 0.0px 0.0px 0.0px; text-align: justify; font: 14.0px Times; min-height: 18.0px} p.p11 {margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Times} p.p12 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Times; min-height: 18.0px} -->Látván a remek <a href="http://www.getharvest.com/">Harvest</a>, <a href="http://www.freshbooks.com/">FreshBooks</a>, vagy az európai <a href="http://invoicemachine.com/home">InvoiceMachine</a> rendszereket bizony elszomorító, hogy Magyarországon miért kellett körbebástyázni ezt a területet egy mikrovállalkozásnak nem betartható szabályokkal, amikhez hasonló más országokban (értsd: Egyesült Királyság és Amerikai Egyesült Államok &#8212; elvégre sznob vagyok) nem léteznek.<span id="more-205"></span></p>
<p>Azonban ha jobban végiggondoljuk az egészet, a bástyasor nem más, mint egy foghíjas szita. Tehát szerintem az alábbi mód teljesen helyes:</p>
<p><span style="font-size: 16px; font-family: Georgia, 'Bitstream Charter', serif; line-height: 24px;"> </span></p>
<ol>
<li>A vállalkozó elindítja az Office 2010-et, kiválaszt egy számla template-et.</li>
<li>Előző kibocsátott számláira hagyatkozva új számlasorszámot választ, és készít egy számlát a megrendelőnek. Ebből két sorszámozott példányt készít: egy 1. példányt PDF-be nyomtat, egy 2. példányt pedig papírra. Mindeközben készít egy 2. példányt is PDF formátumban.</li>
<li>Az 1. példányt ízlése szerint GPG kulcsával aláír, és esetleg a megrendelő kulcsával titkosít. Ezt a példányt elküldi email-ben a megrendelőnek.</li>
<li>A 2. példány papír változatát eljuttatja a könyvelőjének, a PDF változatot pedig saját dokumentumtárában elmenti (lehet, hogy erre 3. példányt kéne használni?)</li>
<li>A megrendelő megkapja az első példányt, és a szerződésben foglaltak szerint kinyomtatja, és beteszi a saját könyvelésébe.</li>
</ol>
<p>&nbsp;</p>
<p>Mi akadályozna meg ebben? A PM rendelet? Lássuk:</p>
<p><strong><em> </em></strong></p>
<p style="padding-left: 30px;"><strong><em>Számítástechnikai eszköz útján, papírra nyomtatott számla adóigazgatási azonosításra való alkalmasságának szabályai</em></strong></p>
<p style="padding-left: 30px;"><strong>1/E. § </strong>(1) Számítástechnikai eszköz útján előállított és papírra nyomtatott számla abban az esetben alkalmas adóigazgatási azonosításra, ha szigorú számadás alá vonása úgy valósul meg, hogy</p>
<p style="padding-left: 30px;"><em>a) </em>a számla kibocsátására szolgáló számítástechnikai program (a továbbiakban: számlázó program) &#8211; a (4)-(6) bekezdésben meghatározott eltérésekkel &#8211; kihagyás és ismétlés nélkül, folyamatosan biztosítja a sorszámozást, továbbá</p>
<p>A számítástechnikai program nem más, mint az Office 2010, ami teljesen alkalmas kihagyás és ismétlés nélkül biztosítani a sorszámozást, sőt, még annál sokkal többet is tud. Persze nem automatikusan, de ez nincs is megkövetelve. Az alkalmasság pedig ugye megvan.</p>
<p style="padding-left: 30px;"><em>b) </em>a számlapéldányok hiánytalan elszámolása az 1/F. § és az 1/H. § szerint biztosított.</p>
<p>Ezeket majd talán ott.</p>
<p style="padding-left: 30px;">(2) A számla kibocsátójának a számlázó program olyan dokumentációjával kell rendelkeznie, amely tartalmazza a program működésére, használatára vonatkozó részletes leírást, valamint a program készítője vagy jogutódja által a számla kibocsátójának címzett írásos nyilatkozatát arról, hogy az maradéktalanul megfelel a vonatkozó jogszabályi előírásoknak.</p>
<p>Az Office 2010 dokumentációja, ami mellesleg csak elektronikusan elérhető, a szoftver minden részletére kiterjed. Az írásos nyilatkozat pedig a szerződés, amiben az összes olyan jogszabályt feltüntetnek, amiben érintett az Office 2010. A PM rendeletet nem, mert ugye nem egy specifikus probléma megoldására készült a program, azonban minden olyan szabályozásnak megfelel az Office 2010, amelyben a szövegszerkesztőkre vonatkozó előírásokat tartalmazzák (nincs ilyen).</p>
<p style="padding-left: 30px;">(3) A számlázó program a hiányos, hibás, megsemmisült vagy elveszett számlákat is rögzíti.</p>
<p>Rögzíti hát, Save As. Az mindent rögzít.</p>
<p style="padding-left: 30px;">(4) A számlázó program az adóalany nem magyarországi adószámán [Áfa tv. 258. § (3) bekezdés <em>b) </em>és <em>c) </em>pont] történő számlakibocsátásához a belfölditől elkülönített sorszámtartományt határoz meg.</p>
<p>Ebben kifejezetten jó az Office. Azt írok oda, amit akarok, tehát mindenképpen más számlatartományban fogok sorszámot választani a külföldi számlák esetén.</p>
<p style="padding-left: 30px;">(5) A sorszámozás folyamatossága nem sérül, ha</p>
<p style="padding-left: 30px;"><em>a) </em>a csoportos adóalanyiságban [Áfa tv. 8. §] részt vevő tagok belső, egymás közötti kapcsolataiban a számlának nem minősülő egyéb számviteli bizonylat kibocsátása, illetőleg</p>
<p style="padding-left: 30px;"><em>b) </em>a csoportos adóalanyiságban részt vevő tagok külső, harmadik személlyel szembeni kapcsolataiban a számla kibocsátása azonos sorszámtartományon belül történik.</p>
<p>Ezen szabályozások betartása sem nehéz.</p>
<p style="padding-left: 30px;">(6) A sorszámozás folyamatossága nem sérül akkor sem, ha a számla és az Áfa tv. 165. § (1) bekezdés <em>a) </em>pontjában meghatározott számviteli bizonylat kibocsátása azonos sorszámtartományon belül történik.</p>
<p>Szintén, sőt, köszönjük a könnyebbséget.</p>
<p style="padding-left: 30px;"><strong>1/F. § </strong>(1) (nem hatályos)</p>
<p style="padding-left: 30px;">(2) A számítástechnikai eszköz útján előállított és papírra nyomtatott számla kibocsátónál maradó példánya &#8211; papírra nyomtatás helyett &#8211; elektronikus adatállományként is megőrizhető, feltéve, hogy a megőrzés a digitális archiválás szabályairól szóló 114/2007. (XII. 29.) GKM rendelet rendelkezései szerint, annak 3. § <em>a) </em>vagy <em>b) </em>pontjában meghatározott mód valamelyikeként történik.</p>
<p>A lényeg a „helyett” szóban van. Nem helyettesítem a könyvelésben található számlát, hiszen azt papír alapon eljuttatom a könyvelőnek (bár neki is van nyomtatója), és ugyanígy fog járni a megrendelőhöz érkező példány is. Nálam pedig pusztán referenciaként szolgál, nem számlaként.</p>
<p style="padding-left: 30px;">(3) A (2) bekezdés szerint megőrzött adatállomány a számítástechnikai eszköz útján előállított és papírra nyomtatott számla elektronikus változata, amely nem minősül elektronikus úton kibocsátott számlának [Áfa tv. 175. §].</p>
<p>Hoppá, hiába tartottam volna csak elektronikusan, az sem számla? Sosem baj, hiszen papírként van meg a könyvelőnél.</p>
<p style="padding-left: 30px;"><strong><em>Elektronikus úton kibocsátott, illetőleg az ilyen alapon rendelkezésre álló számla adóigazgatási azonosításra való alkalmasságának szabályai</em></strong></p>
<p style="padding-left: 30px;"><strong>1/G. § </strong>Az elektronikus úton kibocsátott, illetőleg az ilyen alapon rendelkezésre álló számla adóigazgatási azonosítására az 1/E. §-t, valamint az 1/H. §-t kell megfelelően alkalmazni.</p>
<p>Rekurzió: lásd rekurzió. Amúgy sem vonatkozik ránk, hiszen az elektronikus úton kibocsátott valamilyen oknál fogva a jogalkotóknál teljesen más értelmezésben él, mint az összes többi emberben. Ez áll az ÁFA törvény értelmező rendelkezéseiben:</p>
<p style="padding-left: 30px;">5. <em>elektronikus úton kibocsátott számla: </em>a termék beszerzője, szolgáltatás igénybevevője részére az adatok vagy &#8211; digitális tömörítés felhasználásával &#8211; adatállományok elektronikus úton történő továbbítása, személyes rendelkezésre bocsátása telefonvezetékes, rádiós, optikai vagy egyéb elektromágneses rendszeren keresztül, elektronikus adatfeldolgozás céljára;</p>
<p>TEHÁT ha nem elektronikus adatfeldolgozás céljára továbbítom elektronikusan vagy személyesen a PDF-et, nem minősül digitális úton kibocsátott számlának! A nyomtatás pedig itt nem elektronikus adatfeldolgozás, mert csak a belőle készült papír alapú számlát fogják feldolgozni.</p>
<p style="padding-left: 30px;"><strong><em>A számítástechnikai eszköz útján, papírra nyomtatott számla és az elektronikus úton kibocsátott, illetőleg az ilyen alapon rendelkezésre álló számla adóigazgatási azonosításra való alkalmasságának közös szabályai</em></strong></p>
<p style="padding-left: 30px;"><strong>1/H. § </strong>(1) Az elektronikus úton kibocsátott, illetőleg az ilyen alapon rendelkezésre álló számla és az 1/F. § (2) bekezdés szerint megőrzött számla helyszíni ellenőrzése során az adóhatóság részére</p>
<p style="padding-left: 30px;"><em>a) </em>biztosítani kell a számla olvashatóságához szükséges technikai eszközöket,</p>
<p style="padding-left: 30px;"><em>b) </em>rendelkezésre kell bocsátani az <em>a) </em>pontban említett eszközök használatára vonatkozó dokumentációt, továbbá</p>
<p style="padding-left: 30px;"><em>c) </em>meg kell adni az <em>a) </em>pontban említett eszközök használatához szükséges felvilágosítást.</p>
<p>Hmm. Adjak nekik szemüveget? Mi ez a slendriánság az 1/E. b)-ben?</p>
<p style="padding-left: 30px;">(2) Az adóhatóság jogosult a számla kiállításának folyamatát úgy is ellenőrizni, hogy felügyelete alatt a számla kiállítója &#8211; próbajelleggel &#8211; állít ki számlát.</p>
<p>Bárkit szívesen megtanítok a szövegformázás alapjaira Office 2010 alatt, amennyiben hajlandó a tanfolyamot kifizetni.</p>
<p>Na, ha nem a PM rendelet, akkor bizonyára az ÁFA törvény. Ott az érdekes rész a 175.§-nál kezdődik:</p>
<p style="padding-left: 30px;"><strong>175. §</strong> (1) Számlát elektronikus úton kibocsátani, illetőleg ilyen alapon rendelkezésre álló számlára e törvényben szabályozott jogot alapítani, kizárólag abban az esetben lehet, ha a számla és az abban foglalt adattartalom sértetlensége és eredetiségének hitelessége biztosított.</p>
<p>A számlát papír alapon bocsátjuk ki, melyben felhatalmazást adok az ügyfélnek, hogy a kibocsátás megvalósítását (ti. a számla kinyomtatását) az általam rendelkezésére bocsátott adattartalommal (ti. a PDF alapján) tegye meg. Amennyiben *bármelyikünknek* kételyei támadnának az adattartalom helyességéről, azt mi, egymás között a remek GnuPG titkosító rendszerrel tudjuk mégis biztosítani. Ismétlem, maguk a GPG-titkosított és aláírt fájlok nem minősülnek elektronikusan kibocsátott számlának, csak elektronikusan kibocsátott számla adattartalomnak, amelyből később egy konvencionális számla fog születni.</p>
<p style="padding-left: 30px;">(2) Az (1) bekezdésben említett követelménynek való megfelelés érdekében az elektronikus úton kibocsátott számlát</p>
<p style="padding-left: 30px;"><em>a) </em>az elektronikus aláírásról szóló törvény rendelkezései szerinti, legalább fokozott biztonságú elektronikus aláírással és minősített szolgáltató által kibocsátott időbélyegzővel kell ellátni; vagy</p>
<p>Csakcsupán kérdés, nem tartozik ide: minek a minősített szolgáltató által kibocsátott időbélyegző, ha már fokozott biztonságú elektronikus aláírással is elláttuk? A papír alapú számla nem hazudik, de az elektronikus meg mint a vízfolyás? A számla egyik alapvető eleme a kibocsátás dátuma, ami a dokumentum összes többi elemével együtt digitálisan alá van írva. Tehát akár egy pici részét megváltoztatják, már az aláírás nem fog stimmelni. Ja persze, megvan: nem bízunk senkiben. Üdvözlet a való világban: a számla egy bizalom megtestesülése. Nem mellesleg attól, hogy elektronikusan lett kiállítva, még mindig szükséges, hogy mindkét félnek  rendelkezésére álljon egy-egy példány.</p>
<p>Az egy másik dolog, hogy mit jelent a fokozott biztonságú elektronikus aláírás. GPG-t a saját számítógépemen (csak hogy örüljenek, addig kikapcsolom a wifit, és csak utána dugom be a külső diszket, amin a titkos kulcsom van. Persze lehet ragozni, de minek). Nincs minősítési követelmény.</p>
<p style="padding-left: 30px;"><em>b) </em>az elektronikus adatcsererendszerben (a továbbiakban: EDI) elektronikus adatként kell létrehozni és továbbítani.</p>
<p style="padding-left: 30px;">(3) A (2) bekezdés<em> b) </em>pontja alkalmazásának feltétele, hogy a számlakibocsátásra kötelezett és a termék beszerzője, szolgáltatás igénybevevője előzetesen és írásban megállapodjon az EDI alkalmazásáról és használatáról.</p>
<p style="padding-left: 30px;">(4) A (2) bekezdés<em> b) </em>pontja alkalmazása esetében a számlakibocsátásra kötelezett köteles gondoskodni arról is, hogy havi rendszerességgel az adott hónapban kibocsátott számlákról papíron kiegészítő összesítő jelentés készüljön, és azt a termék beszerzője, szolgáltatás igénybevevője megkapja.</p>
<p style="padding-left: 30px;">(5) Külön jogszabály az (1) bekezdésben említett követelménynek való megfelelés érdekében az elektronikus úton kibocsátott számlára egyéb rendelkezéseket is megállapíthat.</p>
<p>Ó hogyne. Majd ha áttérünk elektronikusan kibocsátott és tárolt számlákra, amit majd az állam rendelkezésünkre ad. Addig maradunk a papírnál, hiszen még mindig a környezet pusztítását követeli meg a törvény, és alternatívaként egy betarthatatlan jogszabály-folyóhomokot biztosít. Ó nem, ott is kell papír alapú kiegészítő összesítő jelentés. De ciki.</p>
<p>Ezek alapján egy Word-ből vagy Excel-ből nyomtatott számlát teljesen hitelesnek lehet elfogadni. Sajnos ettől még mindig nem tudok InvoiceMachine-en keresztül számlázni, de már ez is valami.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.js.hu/2011/04/17/electronic-invoicing-in-hungary-in-hungarian/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Switch to nginx</title>
		<link>http://blog.js.hu/2011/03/05/switch-to-nginx/</link>
		<comments>http://blog.js.hu/2011/03/05/switch-to-nginx/#comments</comments>
		<pubDate>Sat, 05 Mar 2011 21:42:10 +0000</pubDate>
		<dc:creator>js</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[fpm]]></category>
		<category><![CDATA[httpd]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[passenger]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://blog.js.hu/?p=199</guid>
		<description><![CDATA[Every now and then I hear the question: how can I replace apache? It eats too much memory. That&#8217;s true. We started web hosting in small scale. Now we have much more performant machines, even if we&#8217;re still in the &#8230; <a href="http://blog.js.hu/2011/03/05/switch-to-nginx/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Every now and then I hear the question: how can I replace apache? It eats too much memory.</p>
<p>That&#8217;s true. We started web hosting in small scale. Now we have much more performant machines, even if we&#8217;re still in the same scale. And then, we realized we don&#8217;t need this amount of CPU, that amount of RAM, but we still need our stuff separated. We started using VPS.</p>
<p>My usual wise but entirely unhelpful answer was like use nginx. Being an apache user, I couldn&#8217;t even tell whether it will fit in.</p>
<p>Hell, it&#8217;s about time.<img title="More..." src="http://blog.js.hu/wp-includes/js/tinymce/plugins/wordpress/img/trans.gif" alt="" /><span id="more-199"></span></p>
<p>I used to be a hard core FreeBSD user, but currently I maintain only two servers. Both run <a title="Ubuntu Linux" href="http://ubuntu.com/">Ubuntu</a>. I took over the first one, and I moved the second one from a failing system to a VPS. In a hurry. No choice.</p>
<p>Then, I felt it&#8217;s time to update my wiki server in the company I work for, which ran FreeBSD 7.0. I chose Ubuntu Server 10.10 for that.</p>
<p>I have thousands of answers why I switched my beloved multi-jail configuration to a single instance (what, no need to &#8216;ssh tcb&#8217; to see web server logs anymore?), but among them there are interesting stuff like I was unable to compile python 2.7, or <a title="Phusion Passenger" href="http://www.modrails.com/">Phusion Passenger</a> (a.k.a. mod_rails).</p>
<p>The long story short I switched (back) to Linux, and in the mean time I found an interesting application service for PHP, which replaces the last bastion of Apache requirement: mod_php.</p>
<p>Why it&#8217;s interesting, especially for a rails guy? For a ton of reasons: I have users who run a lot of services on the boxes I mentioned earlier, but most of them are WordPress, a couple of MediaWiki instances, and some other stuff, all of them are written in PHP.</p>
<p>We can&#8217;t deny PHP support.</p>
<h3>Enginex screaming</h3>
<p>(sorry for the second bad starcraft2 reference)</p>
<p>In Ubuntu, we can use nginx from the system, but we can use the one which comes with Passenger. Using the latter is better, because U10.10 contains nginx/0.7.67 (legacy version), but Passenger downloads nginx/0.8.54 (stable version). I strongly suggest having both, using Ubuntu&#8217;s configuration framework (which is excellent), while using the newer nginx version.</p>
<p>First, install essential devel packages:</p>
<pre># apt-get install build-essential libcurl4-openssl-dev libssl-dev zlib1g-dev libpcre3 libpcre3-dev</pre>
<p>And set up a ruby you&#8217;d like to use for rails deployments. For now system ruby is more than enough.</p>
<pre># apt-get install nginx ruby ruby1.8-dev rubygems1.8
# gem install --no-ri --no-rdoc passenger</pre>
<p>For some reason, this installs all ruby-generated executables into /var/lib/gems/1.8/bin, but so be it, we&#8217;ll run it only once. Now let&#8217;s build our nginx:</p>
<pre># /var/lib/gems/1.8/gems/passenger-3.0.4/bin/passenger-install-nginx-module</pre>
<p>Now you can select 1) to download, and you can choose /opt/nginx, we&#8217;ll use the executable only. A couple of ENTER pressed, and you&#8217;re done. At the very last screen you can see which lines should you include into http config. Save these two lines and add them to /etc/nginx/conf.d/passenger.conf if you want to use Passenger.</p>
<p>Then, modify /etc/default/nginx to start this new server instead of the default one:</p>
<pre>DAEMON=/opt/nginx/sbin/nginx
DAEMON_OPTS="-c /etc/nginx/nginx.conf"</pre>
<h3>Configure nginx</h3>
<p>The system default configuration is well written: there&#8217;s a default config in /etc/nginx/nginx.conf, you can tweak http settings by putting *.conf files into /etc/nginx/conf.d, and you can set up virtual servers in /etc/nginx/sites-available directory. Then, you can symlink these to sites-enabled like this:</p>
<pre># cd /etc/nginx/sites-enabled
# ln -s ../sites-available/YOURSITE
# /etc/init.d/nginx restart</pre>
<p>Cool, ain&#8217;t it? Let&#8217;s set up a config for a mediawiki site. I have two (or more) subdirectories under the user-editable directory: &#8216;html&#8217; for document root, and &#8216;apps&#8217; for deployed applications. I also put &#8216;tmp&#8217; or &#8216;upload&#8217; for per-site tmp/upload directory, my users don&#8217;t share my tmp.</p>
<pre># cd /srv
# mkdir -p www/mediawiki/apps
# cd www/mediawiki/apps
&lt;download it locally and unzip here to a versioned subdirectory&gt;
# mkdir ../html
# cd ../html
# chown -R www-app: ..
# ln -s ../apps/mediawiki-&lt;version&gt; wiki
# cd wiki
&lt;configure&gt;</pre>
<p>We have the files. Now let&#8217;s set up the web service:</p>
<p>in /etc/nginx/sites-available/&lt;server name&gt;:</p>
<pre>server {
  server_name mediawiki.tld;
  root /srv/www/mediawiki/html;
  location / {
    index index.php index.html index.html;
  }
  location ~ \.php {
    fastcgi_split_path_info ^(.+\.php?)(/.*)$;
    fastcgi_pass unix:/srv/www/sockets/www-data.sock;
    includes fastcgi_params;
  }
  location ~ /\.ht {
    deny all;
  }
  location /wiki/ {
    try_files $uri /wiki/index.php;
  }
}</pre>
<p>It&#8217;s quite a mouthful, let&#8217;s break them down:</p>
<ul>
<li>no listen 80: that&#8217;s the default, why should we bother?</li>
<li>index index.php? Yes, we trigger fastcgi backend by .php ending, and not by a location. Therefore directory =&gt; index page should be handled by the http server instead of fastcgi.</li>
<li>location ~ \.php: Please note we don&#8217;t tell .php should be at the URI&#8217;s end. We have to deal with PATH_INFO after all.</li>
<li>no fastcgi_index index.php? It wouldn&#8217;t fire. Fastcgi settings are triggered by a URI which contains .php in it. Fastcgi_index runs only if $uri is a directory. Therefore it would run only if you have a directory with .php in it&#8217;s name, which is generally not a good idea.</li>
<li>fastcgi_split_path_info: this line does the trick setting PATH_INFO, if specified.</li>
<li>includes fastcgi_params: there is a fastcgi_params file in /etc/nginx, however it&#8217;s not complete. You can find my extra lines below.</li>
<li>location /wiki/ -&gt; try_files: every documentation tells it should be try_files $uri $uri/ &#8230; . However, as we already figured out, .php execution is triggered by explicite inclusion of &#8216;.php&#8217; in the URI. Telling try_files &#8216;$uri/&#8217; just confuses nginx, and index file searching would be skipped.</li>
<li>try_files &#8230; /wiki/index.php: if we want to skip Mediawiki&#8217;s front controller (eg. index.php) from the URL, we can safely say, everything under /wiki can be handled as a PATH_INFO. This just does that. Location strips /wiki from the URI (wrt. location path setting), and this value is passed to /wiki/index.php as PATH_INFO. And in the end, .php location will handle the request. Please note this PATH_INFO setting is totally different from the one we set in .php location. This happens only if no .php has been specified, and the other one applies only to URIs which have .php in them. You can use either or both.</li>
<li>no if (-f&#8230;)? <a title="nginx wiki: If is evil" href="http://wiki.nginx.org/IfIsEvil">If is evil</a>. try_files does a much more decent job anyways.</li>
</ul>
<p>Of course, it&#8217;s not a production ready config, you should have a conf.d/gzip.conf, Expires header to static assets, temporary directory for uploads, error handling, and the like. However this is something we can start working with.</p>
<p>We need three more settings in fastcgi_params file:</p>
<pre>fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  PATH_INFO          $fastcgi_path_info;
fastcgi_param  PATH_TRANSLATED    $document_root$fastcgi_path_info;</pre>
<p>The first line is required if the backend doesn&#8217;t run in chroot. The other two are required to set PATH_INFO-related settings to fastcgi backend.</p>
<p>OK, the hard part is done. Let&#8217;s configure php5-fpm.</p>
<h3>PHP5 FastCGI Process Manager</h3>
<p>In Ubuntu, an &#8216;apt-get install php5-fpm&#8217; will install it. Quite simple.</p>
<p>It comes with a configuration framework too, which is very pleasing. You can find everything in /etc/php5/fpm. There are two files in this directory: main.conf (for fpm config), and php.ini (for php config). You can see two directories too, a conf.d (for extra php config, pointing to /etc/php5/conf.d), and pool.d (for extra fpm config).</p>
<p>I prefer configuring one pool per PHP user, which can be tightened more in conf.d server by server.</p>
<p>For example, this is a standard user&#8217;s pool file:</p>
<p>/etc/php5/fpm/pool.d/USERNAME.conf:</p>
<pre>[username]
listen = /srv/www/sockets/USERNAME.sock
listen.owner = www-data
listen.group = www-data
listen.mode  = 0660
user = USERNAME
group = GROUP

catch_workers_output = true

pm = dynamic
pm.start_servers = 2
pm.max_children = 50
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500</pre>
<p>It listens on a unix domain socket, which is proven to be way efficient than a TCP connection (even in localhost), and it sets listening socket ownership to web server&#8217;s account. We don&#8217;t want anyone else to mess with the data.</p>
<p>Then, it starts a very conservative server. It starts with two servers (+1 for controlling), and at most 50 is spawned. It kills unused servers, keeping 5 at most. It reaps servers which served 500 requests.</p>
<p>My mediawiki config for web service looks like this:</p>
<p>/etc/php5/conf.d/host-mediawiki.conf:</p>
<pre>[PATH=/srv/www/mediawiki]
error_log = /var/log/fpm/mediawiki.log
log_errors = on
display_errors = off
open_basedir = /srv/www/mediawiki/html:/srv/www/mediawiki/tmp
upload_tmp_dir = /srv/www/mediawiki/tmp
session.save_path = /srv/www/mediawiki/tmp</pre>
<p>Please note you have to add a similar config to every single symlink / alias to conf.d. Not doing so would open up the servers to rogue PHP runners <img src='http://blog.js.hu/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Defend yourself then (put it to /etc/php5/conf.d/host-nonexisting.conf):</p>
<pre>[PATH=/]
log_errors = off
display_errors = off
open_basedir = /non_existing_directory</pre>
<p>We&#8217;re done. Now we have replaced apache2 with nginx, and we started serving PHP through php5-fpm, which allows us to run PHP as the serving user, and not as www-data. Oh, and there&#8217;s sugar on top: passenger lets us running ruby (rack) and python (wsgi) apps out of the box!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.js.hu/2011/03/05/switch-to-nginx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Make deployments even more robust</title>
		<link>http://blog.js.hu/2011/02/18/make-deployments-even-more-robust/</link>
		<comments>http://blog.js.hu/2011/02/18/make-deployments-even-more-robust/#comments</comments>
		<pubDate>Fri, 18 Feb 2011 15:39:42 +0000</pubDate>
		<dc:creator>js</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Privát]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[bundler]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[rvm]]></category>
		<category><![CDATA[vlad]]></category>

		<guid isPermaLink="false">http://blog.js.hu/?p=193</guid>
		<description><![CDATA[I&#8217;m sad to say, but me and inploy parted ways. I just need even more robustness in deployment. I don&#8217;t want to get the whole deployment screwed up just because of the git repo cannot be fast-forwarded. I don&#8217;t want &#8230; <a href="http://blog.js.hu/2011/02/18/make-deployments-even-more-robust/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m sad to say, but me and inploy parted ways. I just need even more robustness in deployment. I don&#8217;t want to get the whole deployment screwed up just because of the git repo cannot be fast-forwarded. I don&#8217;t want to screw my deployment on any issue.</p>
<p>I ended up returning to Vlad. The journey to Inploy had it&#8217;s advantage though.<span id="more-193"></span></p>
<h4>What a deployment system should do for us?</h4>
<p>Problem: multiple destinations is a must. You might want to deploy to a production server. To a staging server. To a CI server. You name it. Solution: Vlad honors &#8216;to&#8217; variable. Write your default config to config/deploy.rb, and then, specific config to config/deploy_#{ENV['to']}.rb.</p>
<p>Problem: maybe you have multiple environments (like development server runs passenger, but you run thin with god in staging and production environment). Solution: don&#8217;t set :app or :web options in vlad.rake (set them to nil), and load them in the appropriate deploy_*.rb files.</p>
<p>Cleanup or more setup is required at deployment side. Solution: local rake / thor tasks or generators to be run after setup / update.</p>
<p>Make every deployment independent. Solution: Vlad does this. It clones a vanity repo, and it copies data to a unique, timestamped directory.</p>
<p>Support bundler. Solution: Bundler supports Vlad instead.</p>
<p>Support RVM. It&#8217;s not a simple answer.</p>
<p>First, bash from FreeBSD ports doesn&#8217;t run <strong>any</strong> rc scripts when running remote commands via ssh. My answer was to switch to zsh. FBSD + ssh + zsh == RVM script is loaded. Another option is to wrap every remote task around with bash -lc &#8220;&#8230;&#8221;.</p>
<p>Second, Vlad&#8217;s tasks don&#8217;t honor .rvmrc trust prompts, and &#8216;rvm rvmrc trust &lt;directory&gt;&#8217; is not not quite there. You have to call it twice for every deployment: one for &#8216;releases/<em>DATE</em>&#8216;, and another for &#8216;current&#8217;. Even so, your trust file will grow by every deployment, but won&#8217;t shrink by removing any obsoleted deployments.</p>
<p>There are two possible solutions for this: you can either move project .rvmrc out of your repository (but we all <a title="Vendor Everything Still Applies" href="http://ryan.mcgeary.org/2011/02/09/vendor-everything-still-applies/">know already</a>, your repo should contain .rvmrc), or you can disable this annoying rvmrc trust altogether by adding &#8216;rvm_trust_rvmrcs_flag=1&#8242; into your (or the deploy user&#8217;s) ~/.rvmrc file.</p>
<p>The article I mentioned above the author comes to the conclusion that project rvmrc files should not contain gemset information, only ruby version information. I have played with the idea, and I found it fits well into a deployment concept.</p>
<h4>Gemsets and bundles are basically competing ideas</h4>
<p>Of course there are differences, but basically they&#8217;re here to solve the very same problem: separating projects&#8217; gem environment from others. RVM goes even further, and it changes bundler behavior to work into a gemset. However, bundler does it&#8217;s job better (wrt. dependency resolution), therefore it&#8217;s no need to have two gem environment separation technologies around.</p>
<p>Are gemsets have a use then? Of course they have. Using bundler also means you don&#8217;t have to pollute your default ruby environment with a ton of not needed gems. Sometimes, however, you want to use a tool or another, which are good to be around. Just like when you create a new rails project.</p>
<p>You don&#8217;t have to have the whole rails stack around in your (default) gemset: put it to rails3. And then, when you want to fire up a new project, just type in: &#8216;rvm 1.9.2@rails3 rails new &#8230;&#8217;</p>
<h4>Set up your environments</h4>
<p>That&#8217;s alright, but we still have two environments to sort out: a development and a deployment one. Why it matters? Because development environment is about being easily accessible, but your deployment env. is about to be robust. I strongly suggest vendoring your bundles in development:</p>
<pre>bundle install --path vendor --binstubs --without production</pre>
<p>In deployment, however, I&#8217;d use this:</p>
<pre>bundle install --path ../../shared --deployment --binstubs --without test development</pre>
<p>(you can tweak it for CI for example)</p>
<p>It means all of the binaries will be available in ./bin directory (eg. rake, thor, rspec, all of them). You might want to exclude bundle directory from Vim or Textmate:</p>
<p>Vim:</p>
<p style="padding-left: 30px;">put &#8216;set wildignore+=vendor/ruby/**&#8217; into .vimrc</p>
<p>TextMate:</p>
<p style="padding-left: 30px;">Go TextMate -&gt; Preferences, select Advanced, then Folder Preferences tab. Edit Folder Pattern:</p>
<ul style="padding-left: 30px;">
<li>enclose patterns between starting ! and trailing $ into parens like this: !(.*/(&#8230;))$</li>
<li>add &#8216;|vendor/ruby&#8217; just before closing paren + dollar like this: !(.*(&#8230;)|vendor/ruby)$</li>
</ul>
<p style="padding-left: 30px;">You might want to repeat this for already created projects: open directory, select root directory in project drawer, click on Information button at the bottom right corner in project drawer, repeat steps above.</p>
<p>Deployed environment differs in two places: it works from Gemfile.lock only, and doesn&#8217;t allow any further modifications of Gemfile. The second difference is in bundle directory: we can store bundles in shared directory to save deployment time, it doesn&#8217;t change too often anyways. Of course, if you don&#8217;t concur, you can always use vendor dir.</p>
<p>This is still a work in progress. Any ideas, comments are highly appreciated.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.js.hu/2011/02/18/make-deployments-even-more-robust/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Make rails3 deployment more robust with inploy</title>
		<link>http://blog.js.hu/2010/07/14/make-rails3-deployment-more-robust-with-inploy/</link>
		<comments>http://blog.js.hu/2010/07/14/make-rails3-deployment-more-robust-with-inploy/#comments</comments>
		<pubDate>Wed, 14 Jul 2010 20:35:46 +0000</pubDate>
		<dc:creator>js</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[god-rb]]></category>
		<category><![CDATA[inploy]]></category>
		<category><![CDATA[rails3]]></category>

		<guid isPermaLink="false">http://blog.js.hu/?p=186</guid>
		<description><![CDATA[I never touched Capistrano, it looked like a rake spinoff. I started using Vlad instead (my post in Hungarian), but at some point, it started to be very frustrating. Deployment took too long, deployment versions lost their meaning (you won&#8217;t &#8230; <a href="http://blog.js.hu/2010/07/14/make-rails3-deployment-more-robust-with-inploy/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I never touched <a href="http://www.capify.org/">Capistrano</a>, it looked like a rake spinoff. I started using <a href="http://rubyhitsquad.com/Vlad_the_Deployer.html">Vlad</a> instead (my post in <a title="Negotiations with Hitmen (Hungarian)" href="http://blog.js.hu/2009/05/11/targyalas-a-bergyilkosokkal/">Hungarian</a>), but at some point, it started to be very frustrating. Deployment took too long, deployment versions lost their meaning (you won&#8217;t remember which was the last one which worked well), and all these small things led me to <a title="Inploy on GitHub" href="http://github.com/dcrec1/inploy">Inploy</a> by <a href="http://www.diegocarrion.com/">Diego Carrion</a>.<span id="more-186"></span>Time has passed, and I started feeling the same I felt with Vlad: it started falling into pieces, it was slow, most stuff just didn&#8217;t make sense.</p>
<p>However, I&#8217;m older now, and I tried to find the problem in my own code instead, and I started to rethink what I really want from deployment, and how can I restructure the procedure alongside my new plans.</p>
<p>For now, my target is just a simple app, with no sidekicks like memcached, mongodb, or solr (I definitely plan to have resque), to only one server. It runs on ruby 1.9, in FreeBSD, served by Nginx + Unicorn.  I use ssh+git for repository, and I don&#8217;t want to track deployment versions just another way. This is what I ended up with:</p>
<ul>
<li>I&#8217;ll keep using inploy. It does it&#8217;s job, and it can be extended very easily. However, my original inploy config sucks, and it pulls the wrong triggers.</li>
<li>Deployment tracking is required for staging and production servers, but not on devel servers (yes, I deploy to development servers too, the network is just too baroque for a presentation). The best way to handle them is with git tags. However, inploy doesn&#8217;t support them by default.</li>
<li>Inploy&#8217;s rails3 support is a bit rough. It installs packages to production server you normally use in development or test environments, but you don&#8217;t need them in production. It bundles gems to .bundle subdir, but this is a feature rvm solves in a more elegant way.</li>
<li>Sometimes it&#8217;s required to have different configurations for different deployment environments. In these situations, <code>copy_sample_files</code> is not enough, but rails3 has great feature called generators, just for this.</li>
<li>Inploy doesn&#8217;t support <a href="http://god.rubyforge.org/">god</a> (bluepill, monit, etc.), it has to be implemented.</li>
</ul>
<p>In more general subject, I made the following observations:</p>
<ul>
<li>FreeBSD issue: ruby1.9 native gems don&#8217;t compile, because of the operating system&#8217;s default compiler settings. Ruby Version Manager doesn&#8217;t have this problem. Resolution: use rvm.</li>
<li>Another FreeBSD issue: bash from ports doesn&#8217;t run .bashrc when you want to run commands remotely via ssh. Linux doesn&#8217;t have this shortcoming, and this feature is explicitely in the bash man page even in FBSD. Resolution: use zsh (use Linux is not an option).</li>
<li>Regression of rvm: using a global god installation is not an option. Monit and Bluepill have not been considered, because they require root access. Resolution: every application runs it&#8217;s own god instance, with the user&#8217;s own ruby.</li>
<li>Multiple application deployments in the same box may cause socket naming clashes in god. Resolution: every god instance uses different socket names.</li>
</ul>
<p>Enough idle talk, jump right in! I&#8217;ll go through them, not necessary in the order I&#8217;d actually done it, but in the order you can follow the whole procedure.</p>
<p>First off, you&#8217;ll require git and rvm, with the necessary things added, like ruby version, and bundler installed to the global gemset (global gemset is available in all other gemsets). For the latter:</p>
<pre>$ bash &lt; &lt;( curl http://rvm.beginrescueend.com/releases/rvm-install-head )
$ echo '[[ -s $HOME/.rvm/scripts/rvm ]] &amp;&amp; source $HOME/.rvm/scripts/rvm' &gt;&gt; .rvmstart
$ cat .rvmstart &gt;&gt; .zshenv
$ cat .rvmstart &gt;&gt; .bashrc
$ rm .rvmstart
$ source .rvm/scripts/rvm
$ rvm install 1.9.2
$ rvm use 1.9.2 --default
$ rvm gemset use global
$ gem install bundler --pre</pre>
<p>Continue with inploy config:</p>
<script src="http://gist.github.com/475613.js?file=deploy.rb"></script>
<p>You can see the config uses special server and template setting, as well as a <code>before_restarting_server</code> block for all environments. There&#8217;s another interesting option, <code>deploy.tag</code>: I manage deployments by tags, and it&#8217;s dead simple to revert back to a previous release: just re-deploy the previous, proven tag. Of course, this easiness hides it&#8217;s traps like database version tracking, but it&#8217;s not something we could not solve in finite time. Here comes rails3tags:</p>
<script src="http://gist.github.com/475613.js?file=rails3tags.rb"></script>
<p>Please note setting RAILS_ENV for rake invocation. It is needed because of the tricky bundle installation, which omits test and development groups (and by default it&#8217;d start in development mode).</p>
<p>God manager is lightweight too, but it&#8217;s not a one-liner either:</p>
<script src="http://gist.github.com/475613.js?file=godlike.rb"></script>
<p>It sets up the monitor instance cleanly if it&#8217;s not yet set up, (re)loads all configuration, and restarts the whole task. Not more, not less.</p>
<p>OK, let&#8217;s move forward. Create a new generator:</p>
<pre>$ rails g generator APPNAME/configurations</pre>
<p><strong>Then</strong>, if you still run Rails3.0.0 beta4, or the bug has not been resolved yet, move <code>lib/generators/configurations</code> into <code>lib/generators/APPNAME</code> directory. The generator itself is not a big deal:</p>
<script src="http://gist.github.com/475613.js?file=configurations_generator.rb"></script>
<p>I toyed with the idea of adding a <code>.rvmrc</code> template here, but it is required for first deployment, before any rake tasks can run. Therefore, just put your <code>.rvmrc</code> file in your application root:</p>
<script src="http://gist.github.com/475613.js?file=.rvmrc"></script>
<p>That&#8217;s it! You can test it out:</p>
<pre>$ rake inploy:remote:setup environment=staging
$ rake inploy:up environment=staging</pre>
<p>There&#8217;s one problem though, for me, an inploy:up runs a couple of times, as if some of the rake tasks would be restarted. I&#8217;ll figure it out soon, and I&#8217;ll have this post updated.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.js.hu/2010/07/14/make-rails3-deployment-more-robust-with-inploy/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Getting familiar with Rails 3</title>
		<link>http://blog.js.hu/2010/02/06/getting-familiar-with-rails-3/</link>
		<comments>http://blog.js.hu/2010/02/06/getting-familiar-with-rails-3/#comments</comments>
		<pubDate>Sat, 06 Feb 2010 13:15:07 +0000</pubDate>
		<dc:creator>js</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[authorization]]></category>
		<category><![CDATA[bundler]]></category>
		<category><![CDATA[lockdown]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rails3]]></category>
		<category><![CDATA[ruby1.9]]></category>
		<category><![CDATA[rubygems]]></category>
		<category><![CDATA[shallow nesting]]></category>
		<category><![CDATA[shallow routing]]></category>

		<guid isPermaLink="false">http://blog.js.hu/?p=178</guid>
		<description><![CDATA[With the advent of Rails 3, we have to learn a lot. We have great sources, like a free PeepCode screencast for live upgrade, not mentioning the release notes. I don&#8217;t want to rephrase the install, but some config differences &#8230; <a href="http://blog.js.hu/2010/02/06/getting-familiar-with-rails-3/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>With the advent of Rails 3, we have to learn a lot. We have great sources, like <a href="http://peepcode.com/system/uploads/2010/peepcode-free-004-live-coding-rails-3-upgrade.mov">a free PeepCode screencast</a> for live upgrade,  not mentioning <a href="http://guides.rails.info/3_0_release_notes.html">the release notes</a>. I don&#8217;t want to rephrase the install, but some config differences which make our job easier.<span id="more-178"></span>I took the opportunity to switch to Ruby 1.9 recently, and it seemed natural to continue to use all the old gems I used.  There are slight differences, but this assumption was more or less accurate. There are some issues with encoding, but it&#8217;s not a showstopper. However, when I wanted to run the newly installed rails or rails-update commands, I got a ton of .gemspec errors.</p>
<h2>First issue: ruby and rubygems</h2>
<p>Bundler is the new way to handle your gem dependencies. In the extreme it means you don&#8217;t have to have any other gem installed than bundler. On the other side, ruby 1.9 is bundled (sic!) with rubygems 1.3.1, but the latest bundler requires rubygems &gt;= 1.3.5. As a side note, installing rails 3.0.0.beta requires rubygems 1.3.5 too, because earlier ones didn&#8217;t recognize alphabetic characters in version names. Therefore 1.3.5 is a must.</p>
<p>However, if you update to 1.3.5, you&#8217;ll get errors like &#8216;WARNING: Invalid .gemspec format in &#8230;&#8217;, and rails command will report other errors too.</p>
<p>If you have a look of irb, you can find the culprit:</p>
<p><script src="http://gist.github.com/296725.js?file=Find+rubygems+in+ruby+include+stack"></script> This (&#8230;/lib/ruby/&lt;version&gt;/rubygems*) points to the bundled (v1.3.1) ruby, while the latest one is installed to &#8230;/lib/ruby/site-ruby/&lt;version&gt;/rubygems*. If you have rubygems 1.3.5 installed (gem update &#8211;system), you can remove &#8230;/lib/ruby/&lt;version&gt;/rubygems* by hand, and the problem is gone.</p>
<h2>Second issue: shallow nesting</h2>
<p>It seems rails 3.0.0.beta <a href="https://rails.lighthouseapp.com/projects/8994/tickets/3765-missing-shallow-routes-in-new-router-dsl">doesn&#8217;t have support</a> for <a href="http://guides.rails.info/routing.html#shallow-nesting">shallow nesting</a>. Or at least the new native implementation doesn&#8217;t contain it. The funniest part is it seems nobody cares about it. I use shallow nesting myself, so this is a showstopper for me.  Rails 3&#8242;s router lives in actionpack gem, in ActiveDispatch namespace. Nesting is done by recursive scope changes. The easiest way for manage shallowing the path is to record scope info before scoping, and remove that temporarily from the scope when shallow paths are needed.<br />
 <script src="http://gist.github.com/296725.js?file=mapping.rb"></script></p>
<p>Then, all you have to do is to save the scope in front of resources (keep the root of scope shallowing in @scope[:shallow]), and embed block and member route generation calls in &#8216;with_shallow_scope(saved_scope)&#8217; calls.</p>
<h2>Third problem, phasing out gems</h2>
<p>I&#8217;m using cucumber, rspec, factory_girl for testing, and, most importantly, lockdown for authorization. For now rspec (especially rspec-rails) is not quite there, a lot of stuff has to be rewritten. There is a 2.0.0 alpha prerelease, but it&#8217;s really an alpha.</p>
<p>Factory_girl is in the same boat, while the latest github version can be configured somehow, we still miss a gem for that.</p>
<p>No problem, we&#8217;ll work with no tests for a while (and/or we won&#8217;t actually run the tests). However, user authorization hurts us: lockdown won&#8217;t support rails3.</p>
<p>While I think there&#8217;re a lot of great stuff out there, I couldn&#8217;t yet find anything which would fit my needs. So far we have a lot of great gems out there with excellent DSL&#8217;s (CanCan looks pretty neat!), however they all try to solve the problem in a wrong place.</p>
<p>We got a cartload of hints about using Rack for this stuff. Why don&#8217;t we? Is it really necessary to pollute all of your controllers? Haven&#8217;t you realized that the only place you have to identify authorization is just after routing? Well yes, you can specify that you should be able to do this and that, or you can allow people looking at a page, but they get different response according to their rights. I&#8217;m not even convinced that you don&#8217;t violate the REST principle by this, but it should not be a big deal adding this to the DSL.</p>
<p>Therefore this is my open question: how can I replace authorization in Rails3?</p>
<p>UPDATE: I have made some changes in shallow routing method to keep paths before shallow.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.js.hu/2010/02/06/getting-familiar-with-rails-3/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
			<enclosure url="http://peepcode.com/system/uploads/2010/peepcode-free-004-live-coding-rails-3-upgrade.mov" length="101222856" type="video/quicktime" />
	</item>
		<item>
		<title>Unobtrusive JqGrid on Rails à la 2dconcept, but with Searchlogic</title>
		<link>http://blog.js.hu/2010/01/07/unobtrusive-jqgrid-on-rails-a-la-2dconcept-but-with-searchlogic/</link>
		<comments>http://blog.js.hu/2010/01/07/unobtrusive-jqgrid-on-rails-a-la-2dconcept-but-with-searchlogic/#comments</comments>
		<pubDate>Thu, 07 Jan 2010 08:53:45 +0000</pubDate>
		<dc:creator>js</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[jqgrid]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[searchlogic]]></category>

		<guid isPermaLink="false">http://blog.js.hu/?p=175</guid>
		<description><![CDATA[JqGrid makes our tablework easier on the web, but the original solution is obtrusive. Let&#8217;s see how we can polish it. First, we have to install 2dc_jqgrid, and install it, according to 2dconcept&#8217;s document. I didn&#8217;t want to install squirrel, &#8230; <a href="http://blog.js.hu/2010/01/07/unobtrusive-jqgrid-on-rails-a-la-2dconcept-but-with-searchlogic/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>JqGrid makes our tablework easier on the web, but the original solution is obtrusive. Let&#8217;s see how we can polish it.<span id="more-175"></span></p>
<p>First, we have to install <a href="http://github.com/julian7/2dc_jqgrid/tree/master">2dc_jqgrid</a>, and install it, according to 2dconcept&#8217;s <a href="http://www.2dconcept.com/jquery-grid-rails-plugin">document</a>. I didn&#8217;t want to install squirrel, because I already added <a href="http://github.com/binarylogic/searchlogic/">searchlogic</a>, but since squirrel has will_paginate&#8217;s functionality built in, we have to deal with it ourselves.</p>
<p>Then, let&#8217;s pick an already written CRUD, let&#8217;s call &#8216;users&#8217;, which is tested from the UI side (eg. have a test with Webrat / Selenium / anything similar). This is important: making an unobtrusive page needs testable functionality.</p>
<p>First, let&#8217;s replace the original table with JqGrid:</p>
<p>index.html template (this is haml, but I think it&#8217;s readable):</p>
<pre class="brush: ruby">%table#users
  %tr
    %th= User.human_attribute_name(:username)
    %th= User.human_attribute_name(:email)
    %th= User.human_attribute_name(:tel)
  - @users.each do |user|
    %tr
      %td= h(user.username)
      %td= h(user.email)
      %td= h(user.tel)
      %td
        = link_to t(:show), user
        = link_to t(:edit), edit_user_path(user)
  %tr
    %td{:cols =&gt; "5"}= will_paginate
:ruby
  haml_concat jqgrid(t(".title"), "asdf", "/users",
    [
      { :field =&gt; "id", :label =&gt; "ID", :width =&gt; 35, :resizable =&gt; false },
      { :field =&gt; "username", :label =&gt; User.human_attribute_name(:username), :width =&gt; 100 },
      { :field =&gt; "email", :label =&gt; User.human_attribute_name(:email), :width =&gt; 140 },
      { :field =&gt; "company", :label =&gt; User.human_attribute_name(:company), :width =&gt; 140 },
      { :field =&gt; "tel", :label =&gt; User.human_attribute_name(:tel), :width =&gt; 80, :align =&gt; "center" } ],
    { :height =&gt; 220, :selection_handler =&gt; "users_select_row", :direct_selection =&gt; true })
%p#newuserlink= link_to t(".new"), new_user_path
#userform.popup</pre>
<p>It seems height setting was needed because of some browsers. Selection_handler and direct_selection setting are for future extensions. &lt;div id=&#8221;userform&#8221; class=&#8221;popup&#8221;&gt;&#8230;&lt;/div&gt; will be your popup edit box.</p>
<p>So far so good, let&#8217;s give JqGrid some data:</p>
<p>UsersController#index:</p>
<pre class="brush: ruby">  def index
    @users = User
    @@index_columns ||= [:id, :username, :email, :company, :telephone, :mobile]

    if params[:_search].present?
      if params[:_search] == "true"
        filters = {}
        @@index_columns.each do |param|
          filters[("#{param}_like").to_sym] = "%#{params[param]}%" if params[param].present?
        end
        @users = User.search(filters)
      end
      if params[:sidx].present?
        @users = if params[:sord] == "desc"
          @users.public_send("descend_by_#{params[:sidx]}")
        else
          @users.public_send("ascend_by_#{params[:sidx]}")
        end
      end
    end
    @users = @users.paginate(:page =&gt; params[:page], :per_page =&gt; params[:rows] || 10)

    respond_to do |format|
      format.html
      format.json do
        render :json =&gt; @users.to_jqgrid_json(
          @@index_columns, params[:page], params[:rows], @users.total_entries
        )
      end
    end
  end</pre>
<p>As you can see, we kept html output as is, but we added extra functionality jqgrid search and filter. It&#8217;s a bit more verbose than with Squirrel, but that&#8217;s alright. Now your page should turn the original table to a grid if you have javascript enabled. Let&#8217;s handle our first action: open an in-page popup for editing an entry:</p>
<p>index.html template, annotated:</p>
<p>For first, tell jQuery to ask for Javascript responses to ajax requests:</p>
<pre class="brush: javascript">
jQuery.ajaxSetup({
       'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})</pre>
<p>Then, register events when the page is loaded. Start with New User link in the bottom. Note that inject_userform_submit is called after the response is arrived: we can&#8217;t register the edit form&#8217;s submit event until it&#8217;s loaded, we have to inject the code after we get it loaded.</p>
<pre class="brush: javascript">    $(function() {
      $("#newuserlink").click(function() {
        $.get("/users/new", null, inject_userform_submit, "script");
        return false;
      })</pre>
<p>This is the meat of our popup: I use <a href="http://flowplayer.org/tools/">jQuery Tools</a> for that.</p>
<pre class="brush: javascript">      $(".popup").overlay({
        expose: {
          color: '#fff',
          loadSpeed: 100,
          opacity: 0.5
        }
      })
    })</pre>
<p>Let&#8217;s handle JqGrid&#8217;s row selection callback too, just like #new:</p>
<pre class="brush: javascript">    users_select_row = function(id) {
      $.get("/users/"+id+"/edit", null, inject_userform_submit, "script")
    }</pre>
<p>Last but not least replace the popup edit/new form&#8217;s submit to handle things in Javascript, and make this popup opened:</p>
<pre class="brush: javascript">    inject_userform_submit = function() {
      $("#userform form").submit(function() {
        $.post($(this).attr("action"), $(this).serialize(), null, "script");
        return false;
      })
      $(".popup").overlay().load()
    }</pre>
<p>Now we have requests, let&#8217;s create responses. I really hope everybody puts the form genrator in &#8216;form&#8217; partial, and we can reuse it:</p>
<p>new.js.erb:</p>
<pre class="brush: javascript">$("#userform").html("&lt;%= escape_javascript(render 'form') %&gt;")</pre>
<p>edit.js.erb:</p>
<pre class="brush: javascript">$("#userform").html("&lt;%= escape_javascript(render 'form') %&gt;")</pre>
<p>create.js.erb:</p>
<pre class="brush: ruby">&lt;% if flash.has_key?(:notice) %&gt;
  $("#flashes").html('&lt;div class="flash notice"&gt;&lt;%= escape_javascript(flash.delete(:notice)) %&gt;&lt;/div&gt;')
  $("#users").trigger("reloadGrid")
  $(".popup").overlay().close()
&lt;% else %&gt;
  $("#flashes").html('&lt;div class="flash error"&gt;&lt;%= escape_javascript(flash.delete(:error)) %&gt;&lt;/div&gt;')
  $("#userform").html("&lt;%= escape_javascript(render 'form') %&gt;")
&lt;% end %&gt;</pre>
<p>You can make it more elegant if you have another flash div if you re-render the form.</p>
<p>Then, we have to get UsersController#create and UsersController#update behave differently:</p>
<p>UsersController#create:</p>
<pre class="brush: ruby">    ...
    if @user.save
      flash[:notice] = t('users.create.success')
      respond_to do |format|
        format.html { redirect_to users_path }
        format.js
      end
    else
      flash.now[:error] = t('users.create.failure')
      respond_to do |format|
        format.html { render "new" }
        format.js
      end
    end
    ...</pre>
<p>UsersController#update:</p>
<pre class="brush: ruby">  def update
    @user = User.find(params[:id])
    if @user.update_attributes(params[:user])
      flash[:notice] = t('users.update.success')
      respond_to do |format|
        format.html { redirect_to users_path }
        format.js { render "create" }
      end
    else
      respond_to do |format|
        format.html { render "edit" }
        format.js { render "create" }
      end
    end
  end</pre>
<p>Then, of course, you have to do some CSS magic to make it nice:</p>
<pre class="brush: css">.popup {
  width: 408px;
  display: none;
  border: 2px solid #666;
  background-color: #324; }</pre>
<p>Or, in SASS:</p>
<pre class="brush: ruby">.popup
  :width 408px
  :display none
  :border 2px solid #666
  :background-color #324
</pre>
<p>We have achieved our goals:</p>
<ul>
<li>the original code is still working (run the tests again, you can measure this)</li>
<li>the previous one vice-versa: our tests are still greens</li>
<li>we used our old gems (searchlogic, will_paginate)</li>
<li>the code is unobtrusive, everything works fine if JavaScript is not enabled</li>
</ul>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.js.hu/2010/01/07/unobtrusive-jqgrid-on-rails-a-la-2dconcept-but-with-searchlogic/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Confirmed!</title>
		<link>http://blog.js.hu/2009/09/10/confirmed/</link>
		<comments>http://blog.js.hu/2009/09/10/confirmed/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 16:28:13 +0000</pubDate>
		<dc:creator>js</dc:creator>
				<category><![CDATA[Privát]]></category>

		<guid isPermaLink="false">http://blog.js.hu/?p=172</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><img src="http://blog.js.hu/wp-content/uploads/2baba-out.jpg" alt="2. baba" title="2. baba" class="alignnone size-full wp-image-174" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.js.hu/2009/09/10/confirmed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Add Authlogic and Lockdown to your rails app</title>
		<link>http://blog.js.hu/2009/07/24/add-authlogic-and-lockdown-to-your-rails-app/</link>
		<comments>http://blog.js.hu/2009/07/24/add-authlogic-and-lockdown-to-your-rails-app/#comments</comments>
		<pubDate>Fri, 24 Jul 2009 21:21:53 +0000</pubDate>
		<dc:creator>js</dc:creator>
				<category><![CDATA[Privát]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[lockdown]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby on rails]]></category>

		<guid isPermaLink="false">http://blog.js.hu/?p=171</guid>
		<description><![CDATA[This is not the first time I met Lockdown.  I wanted to use it earlier.  According to the docs, it was awesome.  Real RBAC with no hassle.  However, when I tried to actually use it, it locked my app down. &#8230; <a href="http://blog.js.hu/2009/07/24/add-authlogic-and-lockdown-to-your-rails-app/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is not the first time I met <a href="http://stonean.com/page/lockdown">Lockdown</a>.  I wanted to use it earlier.  According to the docs, it was awesome.  Real RBAC with no hassle.  However, when I tried to actually use it, it locked my app down.  Completely.  In the end I gave up, and started over with <a href="http://www.thoughtbot.com/projects/clearance">Clearance</a>.  It was good and it worked as intended, but it&#8217;s still an authentication layer, with no roles / groups / whatever defined.  I tried <a href="http://github.com/be9/acl9/tree/master">Acl9</a> out too, which did it&#8217;s job, but role definitions were scattered throughout the controllers.  Then I fed up with Clearance too, it made too much noise in my application.  I ended up having <a href="http://github.com/binarylogic/authlogic/tree/master">Authlogic</a> with some sort of Acl9, but it just not felt right.</p>
<p>However, a couple of weeks ago, I noticed that Lockdown reached <a href="http://stonean.com/post/lockdown-1_0">1.0</a>.  Moreover, now it has <a href="http://stonean.com/page/lockdown-with-authlogic">Authlogic support</a>, and even <a href="http://stonean.com/page/lockdown-model-permissions">model-level permissions</a>!  Yikes!  Of course fighting lockdown not to lock down everything was not easy, especially in the tests.  I think it is worth to have my experiences documented.<span id="more-171"></span>I don&#8217;t want to bother you with basic installation.  You can find excellent documentation about it both in <a href="http://github.com/binarylogic/authlogic_example/tree/master">Authlogic</a> and <a href="http://stonean.com/page/lockdown-with-authlogic">Lockdown</a> <a href="http://stonean.com/page/lockdown-model-restriction-use-cases">pages</a>. Go read them.</p>
<p>However, it&#8217;s important to do some other changes, especially if you want to use model-level permssions. Most likely you have a <code>User</code> and a <code>UserGroup</code> model. It&#8217;s wise to connect them with <code>has_and_belongs_to_many</code> in both directions.  Therefore you can ask all groups for a user, and all users for a group with ease.  You can exploit this for granting multiple levels of access:</p>
<p>In Lockdown, you cannot write a permission like this:</p>
<pre class="brush: ruby">set_permission(:user_admin).with_controller(:users)
set_permission(:user_owner).with_controller(:users).
    only_methods(:new, :create).
  and_controller(:users).
    only_methods(:edit, :update).
      to_model(:user).where(:id).equals(:current_user_id)
set_protected_access :users_owner
set_group_access(:usersadmin, :user_admin)</pre>
<p>The problem is if you want to do your stuff as <code>user_admin</code>, restrictions from <code>user_owner</code> creep in, and you won&#8217;t be able to update other users&#8217; data. Therefore, you have to implement this partly in the model, optimizing out intersecting permission settings:</p>
<pre class="brush: ruby">set_permission(:user_admin).with_controller(:users).
  only_methods(:new, :create)
set_permission(:user_owner).with_controller(:users).
  only_methods(:edit, :update).
    to_model(:user).where(:editable_by).includes(:current_user_id)
set_protected_access :users_owner
set_group_access(:usersadmin, :user_admin)</pre>
<p>Then, let&#8217;s implement <code>editable_by</code> in the model:</p>
<p><em>app/models/user.rb:</em></p>
<pre class="brush: ruby">def editable_by
  @editable_by_ids ||= UserGroup.find_by_name("Usersadmin").user_ids | [id]
end</pre>
<p>It&#8217;s simple, ain&#8217;t it? So far so good, but we haven&#8217;t start to write specs (or tests, YMMW). Don&#8217;t hesitate.</p>
<p>You have to have both modules set up properly for testing.  Let&#8217;s write some support code for both (you can fnd a good example for unit tests in <a href="http://github.com/stonean/lockdown-rails-app/tree/master">lockdown-rails-app</a>):</p>
<p><em>spec/support/rbac.rb:</em></p>
<pre class="brush: ruby">require 'authlogic/test_case'
def login_user(group = nil)
  initialize_user(group)
  create_user_session
end

def initialize_user(group)
  @loginuser = Factory.build(:user)
  @loginuser.stub!(:save).and_return(true)
  @loginuser.stub!(:id).and_return(2)
  User.stub!(:find).and_return(@loginuser)
  return if group.nil?
  set_user_group(group)
end

def set_user_group(group)
  ug = Factory(:user_group, :name =&gt; group)
  @loginuser.stub!(:user_groups).and_return([ug])
end

def create_user_session
  activate_authlogic
  @current_user_session = UserSession.create(@loginuser)
  controller.send :add_lockdown_session_values, @loginuser
end</pre>
<p>We could write more, but let&#8217;s face it, we&#8217;re working with real life groups, they should be available. The long story short, all you have to do is to call <code>login_user</code> if you want to manipulate data as a logged in user.  Call <code>login_user("usergroup")</code> if you wan to have group membership. Plain and simple.</p>
<p>Then, all you have to touch is your controller specs (or any test which uses a controller), beside <code>editable_by</code> methods.  It&#8217;s wise to group your tests for guest, normal user, and group member access.  Generally speaking, you can set up normal user tests like</p>
<pre class="brush: ruby">before(:each) do
  login_user
  @loginuser.stub!(:editable_by).and_return([@loginuser.id])
  subject.should_not receive(:access_denied)
end</pre>
<p>However, be prepared for extra model access because of model-level permissions!  It&#8217;s safe to say every model reference will be resolved for the model queried, and if you already have a mock for the query, you have to specify the number of calls:</p>
<pre class="brush: ruby">User.should_receive(:find).twice.and_return(@loginuser.id)</pre>
<p>Apart from these changes, you can develop with Lockdown very easily.</p>
<p>I still haven&#8217;t fixed my cucumber features yet, but I plan to have this solution there also, letting me write all my Given&#8217;s in direct model access.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.js.hu/2009/07/24/add-authlogic-and-lockdown-to-your-rails-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

