<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Daniel Calderón</title>
	
	<link>http://danielcalderon.net</link>
	<description>desarrollo web · diseño de interacción · metodologías ágiles</description>
	<lastBuildDate>Mon, 07 May 2012 13:40:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/danielcalderon" /><feedburner:info uri="danielcalderon" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><creativeCommons:license>http://creativecommons.org/licenses/by/2.0/</creativeCommons:license><item>
		<title>Responsive Design Workflow</title>
		<link>http://feedproxy.google.com/~r/danielcalderon/~3/DyO7ztskicM/</link>
		<comments>http://danielcalderon.net/diseno/responsive-design-workflow/#comments</comments>
		<pubDate>Mon, 07 May 2012 13:40:37 +0000</pubDate>
		<dc:creator>Daniel Calderón</dc:creator>
				<category><![CDATA[diseño]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[responsive design]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://danielcalderon.net/?p=263</guid>
		<description><![CDATA[Responsive Design Workflow View more presentations from Stephen Hay Content Inventory: establish and describe the content. This gives you your raw materials Content reference wireframes: establish rough responsive wireframes in HTML. Allows for really fast iterations. Design in text (structured content): establishes content hierarchy and structure. Easily revisable. Linear Design: Test out the plain jane [...]]]></description>
			<content:encoded><![CDATA[<div style="width:425px" id="__ss_12622715"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/stephenhay/responsive-design-workflow" title="Responsive Design Workflow" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.slideshare.net/stephenhay/responsive-design-workflow?referer=');">Responsive Design Workflow</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/12622715" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.slideshare.net/?referer=');">presentations</a> from <a href="http://www.slideshare.net/stephenhay" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.slideshare.net/stephenhay?referer=');">Stephen Hay</a> </div>
</p></div>
<ul>
<li><strong>Content Inventory</strong>: establish and describe the content. This gives you your raw materials</li>
<li><strong>Content reference wireframes</strong>: establish rough responsive wireframes in HTML. Allows for really fast iterations.</li>
<li><strong>Design in text (structured content)</strong>: establishes content hierarchy and structure. Easily revisable.</li>
<li><strong>Linear Design</strong>: Test out the plain jane structured content in HTML in the browser.</li>
<li><strong>Breakpoint graph</strong>: display visually where the breakpoints happen</li>
<li><strong>Design for various breakpoints</strong>: Start with the small screen first, then expand until it looks like shit.</li>
<li><strong>TIME FOR A BREAKPOINT!</strong></li>
<li><strong>HTML design prototype</strong>: If w’ere not delivering designs in PS, what do we deliver? Clients wants PS because they’re used to it. Create HTML CSS, and maybe a bit of JS</li>
<li>Present prototype screenshots – It’s part of a presentation psychology – Presenting static “impressions” of the design across the different breakpoints allows you to stay ahead of your client.</li>
<li><strong>Present prototype after revisions</strong>: Once revisions have been made, you can show the design in action</li>
<li><strong>Document for production</strong>: Deliver a style guide along with the production code.</li>
</ul>
<p><a href="http://www.the-haystack.com/" onclick="pageTracker._trackPageview('/outgoing/www.the-haystack.com/?referer=');">Stephen Hay</a> (@stephenhay) in <a href="http://bdconf.com/2012/orlando/schedule#stephenhay" onclick="pageTracker._trackPageview('/outgoing/bdconf.com/2012/orlando/schedule_stephenhay?referer=');">Responsive Design Workflow</a></p>
<p>vía <a href="http://bradfrostweb.com/blog/mobile/bdconf-stephen-hay-presents-responsive-design-workflow/?utm_source=feedburner&#038;utm_medium=feed&#038;utm_campaign=Feed%3A+brad-frosts-blog+%28Brad+Frost+Web%29" onclick="pageTracker._trackPageview('/outgoing/bradfrostweb.com/blog/mobile/bdconf-stephen-hay-presents-responsive-design-workflow/?utm_source=feedburner_038_utm_medium=feed_038_utm_campaign=Feed_3A+brad-frosts-blog+_28Brad+Frost+Web_29&amp;referer=');">Brad Frost</a></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/danielcalderon?a=DyO7ztskicM:sq0sf8Y6pXg:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=DyO7ztskicM:sq0sf8Y6pXg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=DyO7ztskicM:sq0sf8Y6pXg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/danielcalderon?i=DyO7ztskicM:sq0sf8Y6pXg:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/danielcalderon/~4/DyO7ztskicM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://danielcalderon.net/diseno/responsive-design-workflow/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://danielcalderon.net/diseno/responsive-design-workflow/</feedburner:origLink></item>
		<item>
		<title>Sub-pixel en Internet Explorer: SASS al rescate</title>
		<link>http://feedproxy.google.com/~r/danielcalderon/~3/osMLf5CEwqo/</link>
		<comments>http://danielcalderon.net/desarrollo-web/css/sub-pixel-en-internet-explorer-sass-al-rescate/#comments</comments>
		<pubDate>Sat, 05 May 2012 11:16:22 +0000</pubDate>
		<dc:creator>Daniel Calderón</dc:creator>
				<category><![CDATA[css]]></category>
		<category><![CDATA[ie]]></category>
		<category><![CDATA[internet explorer]]></category>
		<category><![CDATA[sass]]></category>
		<category><![CDATA[scss]]></category>
		<category><![CDATA[subpixel]]></category>

		<guid isPermaLink="false">http://danielcalderon.net/?p=248</guid>
		<description><![CDATA[Uno de los problemas actuales de aplicar Responsive Design es sin duda el aburrido bug casuado por el Sub-pixel en nuestro odiado Internet Explorer. Para usar Responsive Design versiones de IE inferiores a la 9, recuerda que puedes hacerlo usando Respond.js o css3-mediaqueries-js) ¿En qué consiste? Si visitaste el enlace anterior puedes ahorrarte la siguiente [...]]]></description>
			<content:encoded><![CDATA[<p>Uno de los problemas actuales de aplicar Responsive Design es sin duda el <a href="http://ejohn.org/blog/sub-pixel-problems-in-css/" onclick="pageTracker._trackPageview('/outgoing/ejohn.org/blog/sub-pixel-problems-in-css/?referer=');">aburrido bug casuado por el Sub-pixel</a> en nuestro odiado Internet Explorer.</p>
<blockquote><p>Para usar Responsive Design versiones de IE inferiores a la 9, recuerda que puedes hacerlo usando <a href="https://github.com/scottjehl/Respond" onclick="pageTracker._trackPageview('/outgoing/github.com/scottjehl/Respond?referer=');">Respond.js</a> o <a href="http://code.google.com/p/css3-mediaqueries-js/" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/css3-mediaqueries-js/?referer=');">css3-mediaqueries-js</a>)</p></blockquote>
<p>¿En qué consiste? Si visitaste el enlace anterior puedes ahorrarte la siguiente explicación. Básicamente se resumen en que este problema a la hora de maquetar se da debido al redondeo que hacen los diferentes navegadores al aplicar un porcentaje a un tamaño.</p>
<p>Imaginemos 3 contenedores, de 49, 50 y 51 píxeles cada uno. Dentro de cada uno vamos a crear 4 columnas (usando porcentajes, es decir, width: 25%). ¿Qué tamaño en píxeles tendría cada columna?</p>
<p>Caso 1: 49px x 0.25 = 12.25<br />
Caso 2: 50px x 0.25 = 12.5<br />
Caso 3: 50px x 0.25 = 12.75</p>
<p>Pues aquí está el problema: Webkit (Chrome, Safari, etc&#8230;) y Opera redondean hacia abajo, dejando espacio de sobra. FireFox, IE8, y IE9, modifican el tamaño de las cajas (siendo mayor al esperado) en caso de que sobre espacio por cubrir. Y el inservible IE7 y el menos inservible IE8 para decimales superiores o iguales a .5, redondean hacia arriba, o lo que es lo mismo, para ellos, las columnas serían de 12px, 13px y 13px, haciendo saltar inevitablemente la última columna, maldición nuestra incluída.</p>
<p>Entonces, como ya habrás pensado, la solución es que en nuestra hoja de estilos específicos para IE, le damos menos porcentaje a esas columnas y ya. Y sí, ¿pero cuánto menos? ¿A ojo? Puede servirnos, pero la maquetación no será fiel del todo al diseño original. La solución es:</p>
<blockquote><p>(0.5 / tamaño_del_contenedor) * 100 = 50 / tamaño_de_contenedor</p></blockquote>
<p>Y aquí es donde llega SASS y te hace la vida fácil. Si alguien encuentra una solución mejor, <a href="https://gist.github.com/2600920" onclick="pageTracker._trackPageview('/outgoing/gist.github.com/2600920?referer=');">el gist siguiente</a> es público y puede ser editado a gusto del consumidor :)</p>
<p><script src="https://gist.github.com/2601635.js"> </script></p>
<p>Este post no habría sido posible sin el artículo de <a href="http://tylertate.com/blog/2012/01/05/subpixel-rounding.html" onclick="pageTracker._trackPageview('/outgoing/tylertate.com/blog/2012/01/05/subpixel-rounding.html?referer=');">Tyler Tate</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/danielcalderon?a=osMLf5CEwqo:PrGLMIRK2nE:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=osMLf5CEwqo:PrGLMIRK2nE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=osMLf5CEwqo:PrGLMIRK2nE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/danielcalderon?i=osMLf5CEwqo:PrGLMIRK2nE:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/danielcalderon/~4/osMLf5CEwqo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://danielcalderon.net/desarrollo-web/css/sub-pixel-en-internet-explorer-sass-al-rescate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://danielcalderon.net/desarrollo-web/css/sub-pixel-en-internet-explorer-sass-al-rescate/</feedburner:origLink></item>
		<item>
		<title>Sublime Text 2: el editor de texto definitivo</title>
		<link>http://feedproxy.google.com/~r/danielcalderon/~3/GhMxaecSh30/</link>
		<comments>http://danielcalderon.net/aplicaciones/sublime-text-2-el-editor-de-texto-definitivo/#comments</comments>
		<pubDate>Sat, 28 Apr 2012 18:01:31 +0000</pubDate>
		<dc:creator>Daniel Calderón</dc:creator>
				<category><![CDATA[aplicaciones]]></category>
		<category><![CDATA[editor de texto]]></category>
		<category><![CDATA[sublime text 2]]></category>

		<guid isPermaLink="false">http://danielcalderon.net/?p=245</guid>
		<description><![CDATA[Le prometí fidelidad a Textmate, pero ha sido conocer y probar SublimeText y me ha faltado tiempo para ponerle los cuernos pero bien puestos. Imagino que muchos ya habréis escuchado hablar sobre las bonanzas de Sublime Text 2, y lo cierto es que no son pocas. Detallemos algunas de ellas, solo algunas: Textmate mode: Bundles, [...]]]></description>
			<content:encoded><![CDATA[<p>Le prometí fidelidad a <a href="https://macromates.com/" onclick="pageTracker._trackPageview('/outgoing/macromates.com/?referer=');">Textmate</a>, pero ha sido conocer y probar <a href="http://sublimetext.com" onclick="pageTracker._trackPageview('/outgoing/sublimetext.com?referer=');">SublimeText</a> y me ha faltado tiempo para ponerle los cuernos pero bien puestos.</p>
<p>Imagino que muchos ya habréis escuchado hablar sobre <a href="http://www.sublimetext.com/features" onclick="pageTracker._trackPageview('/outgoing/www.sublimetext.com/features?referer=');">las bonanzas de Sublime Text 2</a>, y lo cierto es que no son pocas. Detallemos algunas de ellas, solo algunas:</p>
<ol>
<li><strong>Textmate mode</strong>: Bundles, Macros, Snippets, &#8230; ¿te suenan? Pues no los echarás de menos</li>
<li><strong>Autocompletado</strong>: sin tener que pulsar la tecla ESC cada vez, un autocompletado de verdad, que ayuda lo que no está en los escritos.</li>
<li><strong>Increíble rapidez de respuesta</strong>: es rápido, pero que muy rápido. Textmate me renqueaba bastante últimamente, en proyectos tanto grandes como pequeños.</li>
<li><strong>Selección múltiple y Multiedición</strong>: esto ya lo tenía Textmate pero no como SublimeText, que nos permite hacerlo en cualquier parte del documento, no necesariamente en línea como ocurría con Textmate.</li>
<li><strong>Auto save</strong>: LA VIDA.</li>
<li><strong>Modo pantalla completa y modo antidistracción</strong>: lo segundo, sobre todo, una de las cosas que más me han gustado. Buscaba algo así en un editor de texto desde hace mucho tiempo.</li>
<li><strong>Búsqueda</strong>: y es que la del Textmate muere con proyectos grandes, y mi Mac con ella, literalmente. La búsqueda de Sublime Text es, parte de funcionar infinitamente mejor, un auténtico gustazo.</li>
<li><strong>Guías</strong>: semi-implementado en Textmate pero mucho mejor resuelto en Sublime Text, me ayuda infinito a la hora de desarrollar.</li>
</ol>
<p>Si te decides a probarlo te aconsejo también:</p>
<ol>
<li><a href="http://wbond.net/sublime_packages/package_control" onclick="pageTracker._trackPageview('/outgoing/wbond.net/sublime_packages/package_control?referer=');">Package Manager</a>: instalación de paquetes/extensiones para Sublime Text.</li>
<li><a href="https://github.com/buymeasoda/soda-theme" onclick="pageTracker._trackPageview('/outgoing/github.com/buymeasoda/soda-theme?referer=');">Soda Theme</a>: aunque Sublime Text trae una buena cantidad de themes, este mola mucho comparado con los que trae por defecto.</li>
<li><a href="https://github.com/phillipkoebbe/DetectSyntax" onclick="pageTracker._trackPageview('/outgoing/github.com/phillipkoebbe/DetectSyntax?referer=');">DetectSyntax</a>: Si algo me volvía loco al principio de SBT era que la sintaxis no cambiaba del todo correctamente (marcaba Ruby cuando era Rails los snippets que necesitaba). Con esta extensión, que puedes instalar desde el Package Control, está todo solucionado.</li>
</ol>
<p>Si voy encontrando más recursos sobre Sublime Text 2 los iré dejando por aquí.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/danielcalderon?a=GhMxaecSh30:tvsFSi9hOCA:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=GhMxaecSh30:tvsFSi9hOCA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=GhMxaecSh30:tvsFSi9hOCA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/danielcalderon?i=GhMxaecSh30:tvsFSi9hOCA:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/danielcalderon/~4/GhMxaecSh30" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://danielcalderon.net/aplicaciones/sublime-text-2-el-editor-de-texto-definitivo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://danielcalderon.net/aplicaciones/sublime-text-2-el-editor-de-texto-definitivo/</feedburner:origLink></item>
		<item>
		<title>‘border-radius’ mixins de andar por casa</title>
		<link>http://feedproxy.google.com/~r/danielcalderon/~3/KNN9yycgh1c/</link>
		<comments>http://danielcalderon.net/desarrollo-web/css/border-radius-mixins-de-andar-por-casa/#comments</comments>
		<pubDate>Mon, 28 Nov 2011 19:45:44 +0000</pubDate>
		<dc:creator>Daniel Calderón</dc:creator>
				<category><![CDATA[css]]></category>
		<category><![CDATA[border-radius]]></category>
		<category><![CDATA[compass]]></category>
		<category><![CDATA[mixins]]></category>
		<category><![CDATA[scss]]></category>

		<guid isPermaLink="false">http://danielcalderon.net/?p=234</guid>
		<description><![CDATA[Últimamente estoy dándole algo de caña a Compass y usándolo en algún que otro proyecto. Es un framework CSS increíble, con muchas herramientas para hacernos la vida más fácil a los fronteneros (o al menos a intentarlo). Entre muchas de estas herramientas está el módulo CSS3, que proporciona mixins para propiedades CSS3 como por ejemplo [...]]]></description>
			<content:encoded><![CDATA[<p>Últimamente estoy dándole algo de caña a <a href="http://compass-style.org/reference/compass/" onclick="pageTracker._trackPageview('/outgoing/compass-style.org/reference/compass/?referer=');">Compass</a> y usándolo en algún que otro proyecto. Es un framework CSS increíble, con muchas herramientas para hacernos la vida más fácil a los fronteneros (o al menos a intentarlo). Entre muchas de estas herramientas está el módulo CSS3, que proporciona mixins para propiedades CSS3 como por ejemplo border-radius. Os animo a darle una oportunidad a este fantástico framework, nos os decepcionará.</p>
<p>En cualquier caso, si no os da por probar Compass, pero usáis <a href="http://sass-lang.com" onclick="pageTracker._trackPageview('/outgoing/sass-lang.com?referer=');">SCSS</a> y estáis hartos de repetiros como loros en vuestro código (<a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Don_t_repeat_yourself?referer=');">DRY!</a>) estáis tardando en utilizar mixins y variables para solucionarlo. Aquí os dejo un &#8216;mixin casero&#8217; para la propiedad border-radius, que no es (pero casi) como los de Compass, pero dan el apaño. Enjoy it!</p>
<p><script src="https://gist.github.com/1401658.js"></script></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/danielcalderon?a=KNN9yycgh1c:aJO_8jDFgp4:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=KNN9yycgh1c:aJO_8jDFgp4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=KNN9yycgh1c:aJO_8jDFgp4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/danielcalderon?i=KNN9yycgh1c:aJO_8jDFgp4:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/danielcalderon/~4/KNN9yycgh1c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://danielcalderon.net/desarrollo-web/css/border-radius-mixins-de-andar-por-casa/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://danielcalderon.net/desarrollo-web/css/border-radius-mixins-de-andar-por-casa/</feedburner:origLink></item>
		<item>
		<title>Desactivar Spotlight</title>
		<link>http://feedproxy.google.com/~r/danielcalderon/~3/ap7ZI_F2zzI/</link>
		<comments>http://danielcalderon.net/general/desactivar-spotlight/#comments</comments>
		<pubDate>Tue, 27 Sep 2011 06:59:09 +0000</pubDate>
		<dc:creator>Daniel Calderón</dc:creator>
				<category><![CDATA[general]]></category>
		<category><![CDATA[lion]]></category>
		<category><![CDATA[macos]]></category>
		<category><![CDATA[spotlight]]></category>

		<guid isPermaLink="false">http://danielcalderon.net/?p=231</guid>
		<description><![CDATA[Fácil y rápido. Para desactivar la indexación, en consola haremos: Si por cualquier motivo queremos volver a reactivarlo y además limpiar la indexación anterior:]]></description>
			<content:encoded><![CDATA[<p>Fácil y rápido. Para desactivar la indexación, en consola haremos:</p>
<pre class="brush: bash; title: ; notranslate">
sudo mdutil -i off
</pre>
<p>Si por cualquier motivo queremos volver a reactivarlo y además limpiar la indexación anterior:</p>
<pre class="brush: bash; title: ; notranslate">
sudo mdutil -i on / &amp;&amp; sudo mdutil -E /
</pre>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/danielcalderon?a=ap7ZI_F2zzI:tl36jWhC22Q:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=ap7ZI_F2zzI:tl36jWhC22Q:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=ap7ZI_F2zzI:tl36jWhC22Q:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/danielcalderon?i=ap7ZI_F2zzI:tl36jWhC22Q:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/danielcalderon/~4/ap7ZI_F2zzI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://danielcalderon.net/general/desactivar-spotlight/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://danielcalderon.net/general/desactivar-spotlight/</feedburner:origLink></item>
		<item>
		<title>validates uniqueness y Shoulda</title>
		<link>http://feedproxy.google.com/~r/danielcalderon/~3/HQ6VZp6ug1E/</link>
		<comments>http://danielcalderon.net/desarrollo-web/ruby-on-rails/validates-uniqueness-y-shoulda/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 09:17:20 +0000</pubDate>
		<dc:creator>Daniel Calderón</dc:creator>
				<category><![CDATA[ruby on rails]]></category>
		<category><![CDATA[factory girl]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[shoulda]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[uniqueness]]></category>
		<category><![CDATA[validates_uniqueness_of]]></category>

		<guid isPermaLink="false">http://danielcalderon.net/?p=225</guid>
		<description><![CDATA[Generalmente utilizo Factory Girl y Shoulda para testear aplicaciones rails. El primero os lo recomiendo y sobre Shoulda, aunque siempre me da algún que otro dolor de cabeza, también me da muchas satisfacciones. Hoy me encontraba en la tesitura de testear que un atributo tuviera un valor único. Si incluimos el test correspondiente con shoulda [...]]]></description>
			<content:encoded><![CDATA[<p>Generalmente utilizo <a href="http://github.com/thoughtbot/factory_girl/" onclick="pageTracker._trackPageview('/outgoing/github.com/thoughtbot/factory_girl/?referer=');">Factory Girl</a> y <a href="http://github.com/thoughtbot/shoulda" onclick="pageTracker._trackPageview('/outgoing/github.com/thoughtbot/shoulda?referer=');">Shoulda</a> para testear aplicaciones rails. El primero os lo recomiendo y sobre Shoulda, aunque siempre me da algún que otro dolor de cabeza, también me da muchas satisfacciones.</p>
<p>Hoy me encontraba en la tesitura de testear que un atributo tuviera un valor único.</p>
<pre class="brush: ruby; title: ; notranslate">
class Example &lt; ActiveRecord::Base
  validates :name, :uniqueness =&gt; true
end
</pre>
<p>Si incluimos el test correspondiente con shoulda nos da un error del tipo <strong>should require case sensitive unique value for</strong> &#8230; Para solucionarlo basta con incluir la primera línea que podéis leer en el test:</p>
<pre class="brush: ruby; title: ; notranslate">
class ExampleTest &lt; ActiveSupport::TestCase
  subject { Factory(:example) }
  should validate_uniqueness_of(:name)
end
</pre>
<p><code>should validate_uniqueness_of</code> necesita tener un registro creado y con <code>subject</code> conseguimos tal objetivo. Podéis obtener más información sobre subject, que es bastante interesante, en la <a href="http://rubydoc.info/gems/shoulda/2.10.3/Shoulda/InstanceMethods" onclick="pageTracker._trackPageview('/outgoing/rubydoc.info/gems/shoulda/2.10.3/Shoulda/InstanceMethods?referer=');">documentación de Shoulda</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/danielcalderon?a=HQ6VZp6ug1E:6T46FBz3lCA:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=HQ6VZp6ug1E:6T46FBz3lCA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=HQ6VZp6ug1E:6T46FBz3lCA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/danielcalderon?i=HQ6VZp6ug1E:6T46FBz3lCA:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/danielcalderon/~4/HQ6VZp6ug1E" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://danielcalderon.net/desarrollo-web/ruby-on-rails/validates-uniqueness-y-shoulda/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://danielcalderon.net/desarrollo-web/ruby-on-rails/validates-uniqueness-y-shoulda/</feedburner:origLink></item>
		<item>
		<title>Comenzar un proyecto desde 0 con Ruby 1.9.2, Rails 3.1 y Mongodb</title>
		<link>http://feedproxy.google.com/~r/danielcalderon/~3/C-9B60dFLVo/</link>
		<comments>http://danielcalderon.net/desarrollo-web/ruby-on-rails/comenzar-proyecto-ruby-1-9-2-rails-3-1-mongodb-mongoid/#comments</comments>
		<pubDate>Sat, 27 Aug 2011 10:26:02 +0000</pubDate>
		<dc:creator>Daniel Calderón</dc:creator>
				<category><![CDATA[ruby on rails]]></category>
		<category><![CDATA[homebrew]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[mongoid]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rails 3.1]]></category>
		<category><![CDATA[rvm]]></category>

		<guid isPermaLink="false">http://danielcalderon.net/?p=219</guid>
		<description><![CDATA[En lo último que ando metido en mis ratos libres es en aprender un poco sobre otros tipos de base de datos. Usualmente suelo trabajar con MySQL pero tenía ganas de probar una base de datos documental, en este caso, MondoDB. Para trastear MongoDB he empezado un proyectillo simple donde aplicar todo lo que vaya [...]]]></description>
			<content:encoded><![CDATA[<p>En lo último que ando metido en mis ratos libres es en aprender un poco sobre otros tipos de base de datos. Usualmente suelo trabajar con <strong>MySQL</strong> pero tenía ganas de probar una base de datos documental, en este caso, <a title="MongoDB" href="http://www.mongodb.org/" onclick="pageTracker._trackPageview('/outgoing/www.mongodb.org/?referer=');">MondoDB</a>.</p>
<p>Para trastear MongoDB he empezado un proyectillo simple donde aplicar todo lo que vaya aprendiendo. El proyecto será en <strong>Rails 3.1</strong> y utilizaré <a href="http://mongoid.org/" onclick="pageTracker._trackPageview('/outgoing/mongoid.org/?referer=');">Mongoid</a>, un ODM (Object-Document-Mapper) muy amigable para los que ya estamos acostumbrados a <strong>ActiveRecord</strong>. En este primer post os voy a contar los pasos que he seguido para poner en pie el entorno de trabajo:</p>
<p>Antes que nada, tendremos en cuenta que vamos a utilizar Ruby 1.9.2. Para trabajar con diferentes entornos de desarrollo Ruby utilizo <a href="http://beginrescueend.com/" onclick="pageTracker._trackPageview('/outgoing/beginrescueend.com/?referer=');">RVM</a>. Una vez tengas instalado Ruby 1.9.2, cambia a ese entorno de desarrollo con <code>rvm use 1.9.2</code>.</p>
<p>Ahora a instalar MongoDB:</p>
<pre class="brush: bash; title: ; notranslate">
brew update
brew install mongodb
</pre>
<p>Con la primera línea actualizamos las formulas de <a href="http://mxcl.github.com/homebrew/" onclick="pageTracker._trackPageview('/outgoing/mxcl.github.com/homebrew/?referer=');">homebrew</a>, el instalador de paquetes con el que trabajo. Si no lo conoces, dale una oportunidad, merece la pena. Una vez instalado mongodb, sigue los pasos que te vayan indicando y, para comprobar que todo ha ido correctamente, prueba a ejecutar <code>mongod</code> y acceder a <em>http://localhost:28017</em>.</p>
<p>Lo siguiente es empezar el proyecto de rails. Lo importante es evitar que utilice ActiveRecord:</p>
<pre class="brush: bash; title: ; notranslate">
rails new myproject -O
</pre>
<p>Esto basicamente crea tu proyecto Rails con todo lo necesario para trabajar con MongoDB. Puedes ver qué hace realmente viendo la documentación de MongoDB, donde explican <a href="http://www.mongodb.org/display/DOCS/Rails+3+-+Getting+Started" onclick="pageTracker._trackPageview('/outgoing/www.mongodb.org/display/DOCS/Rails+3+-+Getting+Started?referer=');">cómo trabajar con Rails</a>.</p>
<p>Ahora vamos a hacer un alto en el camino. Es una buena práctica con rvm definir un gemset por proyecto, para evitar posibles conflictos. Lo explica muy bien <a href="http://railsatope.blogspot.com/2011/06/cambio-automatico-de-gemsets-con-rvm.html" onclick="pageTracker._trackPageview('/outgoing/railsatope.blogspot.com/2011/06/cambio-automatico-de-gemsets-con-rvm.html?referer=');">Javi Baena en su blog</a>. Accedemos al directorio de nuestro proyecto <code>/myproject</code> y creamos un fichero .rvmrc que incluya lo siguiente:</p>
<pre class="brush: bash; title: ; notranslate">
rvm --create use 1.9.2@myproject
</pre>
<p>Sal del directorio del proyecto y vuelve a entrar. Si no había ningún gemset con el nombre myproject lo creará y cambiará a él de manera automática. Como ves, esto es de mucha ayuda cuando tienes varios proyectos en diferentes entornos de desarrollo, no tienes que estar pensando qué entorno utiliza cada uno y demás. Muy útil.</p>
<p>Bien, ahora vamos con el último paso, <a href="http://mongoid.org" onclick="pageTracker._trackPageview('/outgoing/mongoid.org?referer=');">Mongoid</a>. Simplemente incluye en tu <code>Gemfile</code>:</p>
<pre class="brush: ruby; title: ; notranslate">
gem &quot;mongoid&quot;, &quot;~&gt; 2.1&quot;
gem &quot;bson_ext&quot;, &quot;~&gt; 1.3&quot;
</pre>
<p>Y para terminar, en consola:</p>
<pre class="brush: bash; title: ; notranslate">
bundle install
rails g mongoid:config
</pre>
<p>Con la última línea creamos el fichero de configuración que necesita Mongoid (config/mongoid.yml). En su página oficial puedes las diferentes opciones que se pueden incluir en este fichero.</p>
<p>Como primera toma de contacto no está nada mal, ahora toca pelearse con MongoDB. Te recomendaría ver el <a href="http://railscasts.com/episodes/238-mongoid" onclick="pageTracker._trackPageview('/outgoing/railscasts.com/episodes/238-mongoid?referer=');">railscast de Ryan Bates sobre Mongoid</a>, donde te cuenta lo mismo que yo y mucho más.</p>
<p><strong>Actualización</strong>: Si os encontráis en el momento de plantear cómo va a ser el esquema de la base de datos, os aconsejo echarle un vistazo a esta <a href="https://www.10gen.com/presentation/mongosf2011/schemabasics" onclick="pageTracker._trackPageview('/outgoing/www.10gen.com/presentation/mongosf2011/schemabasics?referer=');">presentación de Kyle Banker</a>. Intentaré plasmar en un post lo que saque en claro después de verla.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/danielcalderon?a=C-9B60dFLVo:7HbudmyB2UQ:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=C-9B60dFLVo:7HbudmyB2UQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=C-9B60dFLVo:7HbudmyB2UQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/danielcalderon?i=C-9B60dFLVo:7HbudmyB2UQ:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/danielcalderon/~4/C-9B60dFLVo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://danielcalderon.net/desarrollo-web/ruby-on-rails/comenzar-proyecto-ruby-1-9-2-rails-3-1-mongodb-mongoid/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://danielcalderon.net/desarrollo-web/ruby-on-rails/comenzar-proyecto-ruby-1-9-2-rails-3-1-mongodb-mongoid/</feedburner:origLink></item>
		<item>
		<title>Metaprogramación: métodos y delegates</title>
		<link>http://feedproxy.google.com/~r/danielcalderon/~3/qH_xeUr4OOs/</link>
		<comments>http://danielcalderon.net/desarrollo-web/ruby-on-rails/metaprogramacion-metodos-delegates/#comments</comments>
		<pubDate>Thu, 18 Aug 2011 14:18:54 +0000</pubDate>
		<dc:creator>Daniel Calderón</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruby on rails]]></category>
		<category><![CDATA[delegate]]></category>
		<category><![CDATA[metaprogramación]]></category>

		<guid isPermaLink="false">http://danielcalderon.net/?p=211</guid>
		<description><![CDATA[En el proyecto que estoy trabajando ahora mismo necesitamos diferenciar en vista ciertos elementos en función del tipo al que pertenecen. Sin embargo, el tipo no está asociado directamente a ellos. Para entendernos: Un tipo consta de nombre y label. Para saber si un Item es de un tipo concreto podemos solucionarlo facilmente con un [...]]]></description>
			<content:encoded><![CDATA[<p>En el proyecto que estoy trabajando ahora mismo necesitamos diferenciar en vista ciertos elementos en función del tipo al que pertenecen. Sin embargo, el tipo no está asociado directamente a ellos. Para entendernos:</p>
<pre class="brush: ruby; title: ; notranslate">
class Kind &lt; ActiveRecord::Base
  has_many :items
end

class Item &lt; ActiveRecord::Base
  belongs_to :kind
end

class ItemData &lt; ActiveRecord::Base
  belongs_to :item
end
</pre>
<p>Un tipo consta de nombre y label. Para saber si un Item es de un tipo concreto podemos solucionarlo facilmente con un poco de metaprogramación básica:</p>
<pre class="brush: ruby; title: ; notranslate">
if ActiveRecord::Base.connection.tables.include?('kinds')
  Kind.all.map(&amp;:label).each do |label|
    define_method &quot;#{label}?&quot; do
      self.kind.label == label
    end
  end
end
</pre>
<p>Ahora tenemos métodos como por ejemplo item.a?, item.b?, etc&#8230; Sin embargo, por manos del diablo, en vista no trabajamos directamente con un objeto de tipo Item sino con objetos de tipo ItemData. Si todo estuviera cerradito podríamos hacer cosas como:</p>
<pre class="brush: ruby; title: ; notranslate">
class ItemData &lt; ActiveRecord::Base
  belongs_to :item

  delegate :a?, :to =&gt; :item
end
</pre>
<p>Pero no es nuestro caso, no está cerrado. ¿Cómo lo hacemos? Le echamos un ojo a cómo está hecho el método <a href="http://apidock.com/rails/Module/delegate" onclick="pageTracker._trackPageview('/outgoing/apidock.com/rails/Module/delegate?referer=');">delegate</a> y tras poner aquí y quitar allá, nos queda algo como esto:</p>
<pre class="brush: ruby; title: ; notranslate">
class ItemData &lt; ActiveRecord::Base
  belongs_to :item
  if ActiveRecord::Base.connection.tables.include?('kinds')
    Kind.all.map(&amp;:label).each do |label|
      method = label + '?'
      module_eval(&lt;&lt;-EOS, &quot;(__DELEGATION__)&quot;, 1)
         def #{method}
           notice.__send__(#{method.inspect})
         end
       EOS
    end
  end
end
</pre>
<p>Y ya está. Ahora podemos hacer cosas como @item_data.a? y si el día de mañana se añaden tipos, tendremos su método delegate correspondiente.</p>
<p><strong>Actualización</strong>: incluyo un condicional para saber si está disponible o no la tabla Kind, ya que de otro modo, rake ni siquiera nos deja correr migraciones para que exista.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/danielcalderon?a=qH_xeUr4OOs:o4N9IErxyyg:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=qH_xeUr4OOs:o4N9IErxyyg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=qH_xeUr4OOs:o4N9IErxyyg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/danielcalderon?i=qH_xeUr4OOs:o4N9IErxyyg:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/danielcalderon/~4/qH_xeUr4OOs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://danielcalderon.net/desarrollo-web/ruby-on-rails/metaprogramacion-metodos-delegates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://danielcalderon.net/desarrollo-web/ruby-on-rails/metaprogramacion-metodos-delegates/</feedburner:origLink></item>
		<item>
		<title>Dragonfly y procesado de imágenes: problema con el uid</title>
		<link>http://feedproxy.google.com/~r/danielcalderon/~3/zQbCRqWqZ5g/</link>
		<comments>http://danielcalderon.net/desarrollo-web/ruby-on-rails/dragonfly-y-procesado-de-imagenes-problema-con-el-uid/#comments</comments>
		<pubDate>Tue, 26 Jul 2011 17:45:48 +0000</pubDate>
		<dc:creator>Daniel Calderón</dc:creator>
				<category><![CDATA[ruby on rails]]></category>
		<category><![CDATA[dragonfly]]></category>
		<category><![CDATA[procesado de imágenes]]></category>

		<guid isPermaLink="false">http://danielcalderon.net/?p=204</guid>
		<description><![CDATA[Desde hace algún tiempo venimos trabajando en Flowers in Space en un nuevo producto propio que queremos lanzar a Internet. En él, para el tratamiento de imágenes, por diversos motivos que no vienen a cuento, nos decidimos por utilizar Dragonfly, un framework Rack para el tratamiento de imágenes. Dragonfly es una maravilla. Nos abstraemos del [...]]]></description>
			<content:encoded><![CDATA[<p>Desde hace algún tiempo venimos trabajando en Flowers in Space en un nuevo producto propio que queremos lanzar a Internet. En él, para el tratamiento de imágenes, por diversos motivos que no vienen a cuento, nos decidimos por utilizar <a href="https://github.com/markevans/dragonfly" onclick="pageTracker._trackPageview('/outgoing/github.com/markevans/dragonfly?referer=');">Dragonfly</a>, un framework Rack para el tratamiento de imágenes.</p>
<p><strong>Dragonfly</strong> es una maravilla. Nos abstraemos del post procesado de imágenes y cuando necesitamos que cierta imagen esté en un determinado tamaño basta hacer en vista algo tan simple como por ejemplo @album.cover_image.thumb(&#8217;400&#215;200#&#8217;) y él nos sirve la imagen, la guarda donde le hayamos indicado, y nos olvidamos.</p>
<p>Sin embargo, en algunos casos concretos sabemos que no vamos a necesitar más de un tamaño de imagen. Para esos determinados podemos seguir utilizando Dragonfly y post procesar la imagen antes de guardarla. Mi problema era que estaba intentando hacerlo mediante un before_save de toda la vida y el uid de mi imagen no se generaba. Consecuencia: que en realidad no tenía imagen.</p>
<p>He aquí la solución. Imaginemos el caso anterior, un album que tiene una portada (el ejemplo de la documentación de Dragonfly, vaya). Pero sabemos de antemano que cuando mostremos nuestra portada en la web tendrá un tamaño de 50&#215;50 (<em>un poné</em>). Pues al definir el <code>image_accessor</code> en nuestro modelo podemos hacer lo siguiente:</p>
<pre class="brush: ruby; title: ; notranslate">
image_accessor :cover_image do
    after_assign{ |img| img.process!(:thumb, '50x50') }
end
</pre>
<p>Podéis encontrar más ejemplos y otros callbacks en la <a href="http://markevans.github.com/dragonfly/file.Models.html#Callbacks" onclick="pageTracker._trackPageview('/outgoing/markevans.github.com/dragonfly/file.Models.html_Callbacks?referer=');">documentación de Dragonfly</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/danielcalderon?a=zQbCRqWqZ5g:YoHQVZagxVw:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=zQbCRqWqZ5g:YoHQVZagxVw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=zQbCRqWqZ5g:YoHQVZagxVw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/danielcalderon?i=zQbCRqWqZ5g:YoHQVZagxVw:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/danielcalderon/~4/zQbCRqWqZ5g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://danielcalderon.net/desarrollo-web/ruby-on-rails/dragonfly-y-procesado-de-imagenes-problema-con-el-uid/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://danielcalderon.net/desarrollo-web/ruby-on-rails/dragonfly-y-procesado-de-imagenes-problema-con-el-uid/</feedburner:origLink></item>
		<item>
		<title>Error ActiveRecord::ReadOnlyRecord al actualizar atributos</title>
		<link>http://feedproxy.google.com/~r/danielcalderon/~3/vRXNIOybILo/</link>
		<comments>http://danielcalderon.net/desarrollo-web/ruby-on-rails/error-activerecordreadonlyrecord-al-actualizar-atributos/#comments</comments>
		<pubDate>Wed, 09 Mar 2011 22:21:36 +0000</pubDate>
		<dc:creator>Daniel Calderón</dc:creator>
				<category><![CDATA[ruby on rails]]></category>
		<category><![CDATA[ActiveRecord]]></category>
		<category><![CDATA[ActiveRecord::ReadOnlyRecord]]></category>
		<category><![CDATA[controlador]]></category>
		<category><![CDATA[errores]]></category>
		<category><![CDATA[has_many :through]]></category>

		<guid isPermaLink="false">http://danielcalderon.net/?p=195</guid>
		<description><![CDATA[Sigo con mi proyecto final de carrera y poco a poco vamos aprendiendo cosillas nuevas de Rails. Al mismo tiempo que voy picando código en el controlador, modelo y vistas voy testeando, dos frentes de aprendizaje pero que recomiendo a todos los que comiencen en Rails. Aunque al principio avanzas de forma más lenta y [...]]]></description>
			<content:encoded><![CDATA[<p>Sigo con mi proyecto final de carrera y poco a poco vamos aprendiendo cosillas nuevas de Rails. Al mismo tiempo que voy picando código en el controlador, modelo y vistas voy testeando, dos frentes de aprendizaje pero que <strong>recomiendo</strong> a todos los que comiencen en Rails. Aunque al principio avanzas de forma más lenta y te das (como estoy haciendo yo) de bruces contra un muro una y otra vez, a la larga aprendes mucho tanto de tus múltiples errores como de tus aciertos.</p>
<p>Una vez tenía hecho el test de un <em>update</em> supuestamente correcto obtuve un error al actualizar los atributos de un objeto. En primera instancia pensé que había olvidado en el modelo alguna cosa, pero también estaba correcto. Tras una búsqueda en Google <a href="http://stackoverflow.com/questions/639171/what-is-causing-this-activerecordreadonlyrecord-error#answer-639844" onclick="pageTracker._trackPageview('/outgoing/stackoverflow.com/questions/639171/what-is-causing-this-activerecordreadonlyrecord-error_answer-639844?referer=');">encontré la solución</a>.</p>
<p>Extrayendo la explicación del artículo</p>
<blockquote><p>Introduce read-only records. If you call object.readonly! then it will mark the object as read-only and raise ReadOnlyRecord if you call object.save. object.readonly? reports whether the object is read-only. Passing :readonly => true to any finder method will mark returned records as read-only. <strong>The :joins option now implies :readonly, so if you use this option, saving the same record will now fail</strong>. Use find_by_sql to work around.</p></blockquote>
<p>O lo que es lo mismo, si tu objeto lo obtienes tirando de relaciones, por ejemplo, un <em>has_many :through</em>, por debajo está haciendo un INNER JOIN con el modelo intermedio, y ahi está el problema, que el objeto pasa a ser de solo lectura. Las soluciones podrían ser dos:</p>
<ol>
<li>Obligar al objeto a que no sea solo lectura indicando como parámetro del find :readonly => false</li>
<li>Utilizar include en lugar de join, si es posible</li>
</ol>
<p>Hasta aquí lo que venías buscando. Pero si quieres ver un ejercicio práctico sobre relaciones y cómo evitar el <strong>ActiveRecord::ReadOnlyRecord</strong> en él sigue leyendo.</p>
<h4>Ejemplo práctico</h4>
<p>Imaginemos que estamos en el WoW (oh dios, no puedo creer que esté escribiendo esto). Tenemos hermandades (guild) y jugadores (users). Las hermandades pueden tener varios jugadores, de los cuales varios pueden ser Maestre, algo así como los &#8220;admin&#8221; de la hermandad, y puede haber más de un Maestre por hermandad. Además los jugadores pueden estar en varias hermandades.</p>
<p>Seguro que se puede hacer de varias formas, pero nosotros vamos a hacerlo mediante un <em>has_many :through</em>, utilizando como modelo intermedio <em>membership</em>, donde tenemos un campo <em>owner</em> que nos indica si es o no maestre de la hermandad.</p>
<p>Empezamos con los modelos:</p>
<p><strong>guild.rb</strong></p>
<pre class="brush: ruby; title: ; notranslate">
  has_many :memberships
  has_many :users, :through =&gt; :memberships, :uniq =&gt; true
  has_many :owners, :through =&gt; :memberships, :source =&gt; :user, :conditions =&gt; { &quot;memberships.owner&quot; =&gt; true }

  validates_presence_of :name
</pre>
<p>De esta manera si tenemos una hermandad en @guild podemos saber quienes son todos sus miembros haciendo @guild.users y sus maestres @guild.owners.</p>
<p><strong>IMPORTANTE</strong>: Este ejemplo no está completo. Es decir, si hacemos @guild.owners << User.find(5) (por ejemplo) no crea adecuadamente el membership, ya que faltaría marcar el campo owner del membership creado a <em>true</em>. Eso lo dejo para otro post y no seguir complicando las cosas.</p>
<p><strong>user.rb</strong></p>
<pre class="brush: ruby; title: ; notranslate">
  has_many :memberships
  has_many :guilds, :through =&gt; :memberships
  has_many :owned_guilds, :through =&gt; :memberships, :source =&gt; :owner, :conditions =&gt; { &quot;memberships.owner&quot; =&gt; true }
</pre>
<p>De esta manera podemos saber qué hermandades lidera un jugador haciendo @user.owned_guilds y a cuales pertenece (sea maestre o no) haciendo @user.guilds.</p>
<p>De nuevo, <strong>importante</strong>: Este ejemplo no está completo. Es decir, si hacemos @user.owned_guilds << Guild.find(7) (por ejemplo) no crea adecuadamente el membership, ya que faltaría marcar el campo owner del membership creado a <em>true</em>.</p>
<p><strong>ownership.rb</strong></p>
<pre class="brush: ruby; title: ; notranslate">
belongs_to :user
belongs_to :owner, :class_name =&gt; &quot;User&quot;
belongs_to :guild
</pre>
<p>Hasta aquí el ejercicio práctico de relaciones, ahora vamos al lío. Imaginemos que queremos actualizar el nombre de nuestra hermandad. Para hacer esto debes ser maestre de la hermandad. Si tenemos en cuenta que no hemos metido aquí un sistema de permisos (rollo CanCan o similares) podemos solucionar esto de dos formas:</p>
<h5>Buscar y modificar si es posible</h5>
<p><strong>guilds_controller.rb</strong></p>
<pre class="brush: ruby; title: ; notranslate">
def edit
  @guild = Guild.find(params[:id])
end

def update
  @guild = Guild.find(params[:id])
  if @guild.update_attributes(params[:guild])
    redirect_to guild_path(@guild), :success =&gt; &quot;Guild actualizada&quot;
  else
    render :edit
  end
end
</pre>
<p>Algo de refactoring básico:</p>
<p><strong>guilds_controller.rb</strong></p>
<pre class="brush: ruby; title: ; notranslate">

before_filter :get_guild

def edit
end

def update
  if @guild.update_attributes(params[:guild])
    redirect_to guild_path(@guild), :success =&gt; &quot;Guild actualizada&quot;
  else
    render :edit
  end
end

protected

def get_guild
  @guild = Guild.find(params[:id])
end
</pre>
<p>Además vamos a tener aquello de que <strong>actualizar el nombre de la hermandad solo puede hacerlo el maestre</strong>.</p>
<p><strong>guilds_controller.rb</strong></p>
<pre class="brush: ruby; title: ; notranslate">

before_filter :get_guild
before_filter :check_ownerhip

def edit
end

def update
  if @guild.update_attributes(params[:guild])
    redirect_to guild_path(@guild), :success =&gt; &quot;Guild actualizada&quot;
  else
    flash[:error] = &quot;No ha sido posible actualizar los datos de la guild&quot;
    render :edit
  end
end

protected

def get_guild
  @guild = Guild.find(params[:id])
end

def check_ownership
   redirect_to user_path(current_user), :error =&gt; &quot;No tienes permisos&quot; unless current_user.owned_guilds.include?(@guild)
end
</pre>
<p>En este primer ejemplo, no obtenemos un ActiveRecord::ReadOnlyRecord ya que obtenemos la @guild directamente (sin el uso del join de la has_many :through) y el objeto @guild no es de solo lectura. La consulta que se hace a base de datos sería:</p>
<pre class="brush: sql; title: ; notranslate">
SELECT `guilds`.* FROM `guilds` WHERE `guilds`.`id` = 1 LIMIT 1
</pre>
<h5>Tirar de relaciones y 404</h5>
<p>Esta es la segunda forma, donde no vamos a utilizar un before_filter para comprobar si el jugador es maestre de la hermandad. En su lugar vamos a aprovecharnos de que al buscar entre las owned_guilds de un jugador una de la que no sea maestre en Rails obtenemos un ActiveRecord::RecordNotFound, o lo que es lo mismo, un 404.</p>
<p><strong>guilds_controller.rb</strong></p>
<pre class="brush: ruby; title: ; notranslate">
before_filter :get_guild

protected

def get_guild
  @guild = current_user.owned_guilds.find(params[:id])
end
</pre>
<p>El resto de acciones del controlador permanece intacto (exceptuando como dije, el before_filter :check_ownership que no estaría en este segundo ejemplo).</p>
<p>Y ahora&#8230; por fin, ¿y el ActiveRecord::ReadOnlyRecord donde anda en este segundo ejemplo? Pues al hacer @guild = current_user.owned_guilds.find(params[:id]), @guild es de solo lectura, al haber tirado de relaciones.</p>
<p>Suponiendo que el User con id igual a 1 quiere actualizar la Guild con id igual a 1. Lo primera lanzaría la siguiente consulta:</p>
<pre class="brush: sql; title: ; notranslate">
SELECT `guilds`.* FROM `guilds` INNER JOIN `ownerships` ON `guilds`.id = `ownerships`.guild_id WHERE `guilds`.`id` = 1 AND ((`ownerships`.user_id = 1)) LIMIT 1
</pre>
<p>Ahí podéis ver el JOIN al que antes hacía mención. Habiendo un JOIN de por medio, el objeto es de solo lectura. Y no podremos actualizarlo.</p>
<h5>Tío, termina ya, so pesao</h5>
<p>Pues la solución para mantener el segundo ejemplo tal cual y poder actualizar es tan simple como indicar que no es de solo lectura. ¿Cómo?</p>
<pre class="brush: ruby; title: ; notranslate">
before_filter :get_guild

protected

def get_guild
  @guild = current_user.owned_guilds.find(params[:id], :readonly =&gt; false)
end
</pre>
<p>Vaya artículo largo. No tengo remedio. Al menos espero que le sirva a alguien. Y como siempre, si alguien tiene algo que aportar o corregir, dispone de los comentarios para ello, yo lo agradezco un montón.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/danielcalderon?a=vRXNIOybILo:7JlOvkfL7QE:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=vRXNIOybILo:7JlOvkfL7QE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/danielcalderon?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/danielcalderon?a=vRXNIOybILo:7JlOvkfL7QE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/danielcalderon?i=vRXNIOybILo:7JlOvkfL7QE:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/danielcalderon/~4/vRXNIOybILo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://danielcalderon.net/desarrollo-web/ruby-on-rails/error-activerecordreadonlyrecord-al-actualizar-atributos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://danielcalderon.net/desarrollo-web/ruby-on-rails/error-activerecordreadonlyrecord-al-actualizar-atributos/</feedburner:origLink></item>
	</channel>
</rss>

