text:
In reality Ember bundled jQuery with it as one of its "opinions" but the framework itself it not SO dependent on jQuery. There is basically only three features in Ember that rely in it:
click() {} in you components
be called)
But a lot of things have changed since Ember decided that bundling jQuery was a good idea back in 2011. Then jQuery was the thing we all were building things on, mobile web apps were anecdotical at best and IE 7/8 was so popular that few people dared to code stuff for them without the cross-browser safety net of some library.
Today we build apps that run mostly for evergreen browsers and perhaps IE11, mobile accounts for a good 50% of our visits if not more, and making a network request is no longer something that requires you to copy-paste some obscure code from stackoverflow, so it's time to make jQuery one of those Ember opinions you can disagree with.
Before you start following this post, consider if it's worth the effort for you to do this.
If you have an app that is months or years old, it will take significant effort remove jQuery.
It will require refactor ALL your tests, stop using jQuery it in all the places where you did (and I bet
you did in more places than you're aware of) and for now many of the addons your use won't work, starting
with some addons as important as
An intermediate step could be to use a lighter version of jQuery with some features removed.
For you it might make more sense to use the slim version of jQuery, which can save you
7KB with very little effort.
If you are starting a new app right now and it targets mobile, it might make sense to try. You will save more than 35KB of min+gzip size, with it's associated parse and eval code and that can save half a second in a cold boot even with decent device and connection and around a second if other of those is bad.
If, on the other hand, your app targets desktop, it is unlikely that a jQuery-less app will bring you a lot of advantages and it will make your development harder, as a lot of addons need jQuery to work, so you will have to make
PRs to fix other people's addons as you go. It is important to keep in mind that jQuery
is not over 100K of random code someone wrote for the fun of it. It actually fixes tons of browser
quirks (run
curl -L https://code.jquery.com/jquery-git.js | grep -A 5 -n Support: to
see some). It's a fantastic piece of software that we shouldn't disregard as obsolete.
That said, most of those quirks affect IE9 and 10 or ancient versions of safari and the android browser which are legacy today and Ember shields you from almost all of them by handing DOM manipulation, so a lot of Ember addons rely on jQuery for very simple tasks just because it has always been there, not because it is intrinsic to their goal. Usually fixing those addons takes little time.
If you are maintaining an addon, you totally should. Since the main problem people will face building apps without jQuery is that addons break, try to make your addons to not be one of those that break.
Now, let's get to the topic
At the time of this writing, you need Ember.js >= 2.13.0-beta.2. Soon (a few weeks) the fix will be in stable. I'd also strongly recomend to be on ember-cli 2.13-beta too so you use ember-cli-babel 6. It's not required, but in this tutorial I'm going to do it and explain why it's cool.
Since the main missing point of the transition away from jQuery was testing, this post is also going to explain a new way of doing testing that is an experiment towards the Grand Testing Unification RFC that has been long awaited and today we can almost touch it with the tips of our fingers.
On every step I'll explain you why this step is required, because some of them are needed today but will probably not be required in the future as tools adapt. If you read this post in a few weeks or months in the future, recheck if things have changed and skip the step if possible.
The first step is top update your app/addon to use 2.13. Run
ember install firstname.lastname@example.com
The reason for that is this fix that
makes Ember only setup
ajaxSend and
ajaxComplete events only if jQuery is present.
Without it jQuery-less apps where basically untestable.
The second step (entirely optional, feel free to skip): Update ember-cli to 2.13-beta. Go, I'll wait.
One nice feature of this beta version is the new targets feature In short, this feature allows you to express in what browsers your app is going to run so tooling can be smart about it in many ways. The best example of this is that ember-cli-babel 6 will only transpile what is necessary for running the app in the given and nothing else, so if you target only modern browsers, features like arrow functions will not be transpiled.
If you are like me, you will usually develop in the latest chrome. If you do so, you don't need most of the transpilation that Babel does by default even if you do for production, so for a better debugging experience I use this settings:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Your app will be transpiled in production and when running tests in CI but in development,
apart from
import/export, your code will remain almost untouched. I've disabled JS sourcemaps
since I don't find them useful anymore with this settings.
The reason why I recomend following this step even if it's not necessary is because we're going to rely a lot in some new features of the language and avoiding transpilation will make your debugging experience better. I actually recommend those settings regardless of if you plan to remove jQuery or not. It just feels like living in a better future.
The third step is to replace the jQuery-based ember dispatcher that lives inside Ember with one based in native events. As usual Robert Jackson got you covered and he developed ember-native-dom-event-dispatcher a while ago.
ember install ember-native-dom-event-dispatcher and your app will not use jQuery events anymore.
This will make components methods named after events (like
click(event) {} or
mouseEnter(event) {}) work
as usual with the subtle difference that the received
event is no longer a jQuery event but a native one.
For the most part they are pretty interoperable, but there is some subtle differences in props/methods
and how
event.target works, so pay attention.
To name the caveat that is most likely to bite you, to check if some code called
.preventDefault() on an event,
in native events you use the
e.defaultPrevented property while in jQuery events you use the
The forth step if to install the last version I published of ember-native-dom-helpers.
ember install ember-native-dom-helpers and you will be introduced to a new way testing that
will delight you and I'll cover in a moment. This new way of testing is going to use
instead of
andThen, so any but the very latest browsers will need the regenerator
ember install ember-maybe-import-regenerator to get it. This addon already
uses the new targets feature so it will not import it if the browsers you target support async/await already.
I'm biased because I started the work on
ember-native-dom-helpers, but regardless of if you plan to remove jQuery, you should try it.
It's going to make you love your tests again, particularly integration tests.
The next step is to remove
ember-ajax. The addon is included in the default blueprint but it is a wrapper around
$.ajax, so it's evident that we need to find a replacement.
I've switched on my projects to
ember-fetch and it's very nice.
However at the time of this writing you must use the branch
patch-2 of my own
fork of the project (cibernox/ember-fetch#patch-2) while those changes are not
merged into master.
It is important to note that you must not use the global
window.fetch even if your browser matrix supports it.
You must use the
import fetch from 'fetch'; import path that the addon provides.
You might wonder why we can't just "Use the platform". If you don't care about testing then using
is fine, but in testing you will want to perform some operation that makes a network request
and then wait for it to finish before asserting that your UI has updated accordingly.
In order to do that Ember must instrument when a fetch request starts and finishes so it can
wait for them, and that is what this imported
fetch function does. It's just a thin wrapper
over the global fetch with a polyfill for old browsers.
Another reason to not use the native fetch is that you will want to mock network requests in development/test
ember-cli-mirage is very popular for that. That addon
uses a mocking library called Pretender.js which
at the time of this writing cannot mock requests made with the native
fetch, but it can
however if you use the fetch polyfill that
ember-fetch (which uses a regular XHR request underneath) provides you.
There is some ideas to fix pretender on this regard, so hopefully this will change soon.
BTW, there is a caveat about
fetch (native or otherwise) that although I am aware of, I keep forgetting.
$.ajax('/some-url').then(fn1).catch(fn2) where 2XX and 3XX status codes trigger the
then callback
and 4XX and 5XX statuses are considered failures and trigger the
catch, using the
fetch the
only situation that causes a request to fail and the
catch handler to be called is a real
network error, like being offline or a timeout. Any request that was properly sent and
received, even if its status is a catastrofic 500 will call the
then method, so you need to use
response.ok flag to disambiguate. E.g:
1 2 3 4 5 6 7
One last thing you have to remove is
ember-data, for similar reasons. There is a plan to
ember-data from
$.ajax, but we're not there yet.
Enough with addons, let's remove jQuery itself. Open your
ember-cli-build.js and make
it look like this:
1 2 3 4 5 6 7 8 9
Done, no more jQuery. Now if you are on an empty app or addon you should be able boot it and start working on it. If you are on an existing one, chances are some addon will break, but the errors messages I've seen were always pretty evident.
The actual problem until now with jquery-less apps was testing, and this is the problem,
among others, that
ember-native-dom-helpers wants to solve.
This addon provides you with a collection of test helpers that you can use in both acceptance
and integration tests and those helpers, unlike the ones in Ember.js itself, don't use jQuery internally.
It even offers a few useful new helpers like
tap and
waitUntil that will make your life
One key feature of the interaction helpers of that addon (
tap …) is
that they return the promise generated by
wait(), which is a promise that resolves once
the "world has settled" (No pending waiters, no pending route transitions, no pending ajax requests…).
This along with the new
async/await syntax in ES2017 allows you to make your tests much
more readable.
Instead of
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
you can write:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
With the benefit that you don't need to change your mindset when writing integration tests, since the same helpers behave the same way on both kind of tests:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Since those helpers don't use jQuery and now we are making requests with
ember-fetch, we
can write and tests apps nicer than ever!
Note that to prevent ESLint to freak out when using
async/await, you must edit your
file and instruct to parse the javascript as the new ES2017 spec:
1 2 3 4 5 6 7 8 9 10 11 12 13
If you are starting a new project and since the name of the test helpers provided by
ember-native-dom-helpers are the same of the global helpers provided by Ember, but you
really don't want to use those by mistake, I recommend to remove the configuration line
that explicitly whitelists those helpers as globals, so it will prevent you from using
the global
window.click/fillIn that rely on jQuery by mistake.
1 2 3 4 5 6 7
This is pretty much all you need to know about the future of testing and removing jQuery from your app addons. Now it is the turn of the community of steadily but relentlessly make all the addons that are not intentionally wrappers around jQuery plugins to work without it, so soon we move from making jQuery an opt-out to make it an opt-in, which is part of the broader strategy to create an easy path for apps to escalate from a barebone Glimmer.js component to the full-featured Ember.js application as they need.
Yes, it is. This screen were taking on www.ember-basic-dropdown.com running locally with CPU throttling set to 5X and networt set to "Good 3G". That is more or less like using a high end Android devise on a meh connection. A pretty common situation in the first world.
With jQuery:
Without jQuery:
The TTI (time to interactive) is consistently around 0.7 seconds smaller on a cold boot. With a slower device or a worse connection the difference is a bit over one second.
This is for addon maintainers. If you know that your addon doesn't have any reason to use jQuery, what you can do is follow the steps in this tutorial, fix any possible unintended usage of jQuery in your addon and then make sure you test without jQuery in CI.
You can use this PR to ember-basic-dropdown
as an example of the changes that an addon with a mild usage of jQuery had to do to.
This and this
PRs that slowly introduced
ember-native-dom-helpers before chopping jQuery might also
be helpful to see how to refactor a codebase to the new testing style.
This is just what I think should be required to the MVP of a jquery-less world that doesn't suck to live in.
ember-fetch to have some sort of feature-parity with
ember-ajax, particularly exposing a service that allows to encapsulate authentication, headers and all that.
ember-data's internals to use some sort of
network service that masks how that actually works inside. It could be implemented in terms of
fetch or raw
XHR. This service should be provided by the networking libraries (
ember-fetch…). For backwards compatibility reasons probably this service's semantics should mimic
$.ajax, but not sure.
ember-native-dom-event-dispatcher is present in some of the ember-try scenarios.
This posts starts a (probably short) series of post with things I've learned in the process. Some will be concrete tricks, others will be just general advices.
Patronizing bores people, so I'll start with one simple trick.
No, this is not about the well-known old rails security outage.
Imagine you have built a component that, despite of how hard you tried to avoid it, ends up accepting quite a few options. You are a good Ember fellow so you decide to leverage convention over configuration and make most those option have sensible default values.
1 2 3 4 5 6 7 8
{% raw %}
Your goal is to allow a user to be able to create their own wrapper components that compose yours, so they can reuse some set of configuration options and actions that yield the behavior they want in a less verbose manner. That user is also a very good ember citizen and decides that there is value on that customized version of your component and it can be published as an addon.
That user will also want to give some degree of freedom to the consumer of his work and allow to, on turn, customize the default values.
To allow that, the wrapper component must forward all possible attributes to the inner component, like this:
{% raw %}
1 2 3 4 5 6 7 8 9
So the user just does:
And here it comes the problem. If the consumer of the wrapper component doesn't specify every single possible
option those non-specified options being forwarded contain
undefined and will override the default
values of the inner with it.
This is not really easy to fix by the creator of the wrapper component, because to fix that from the outside, the wrapper component has to copy the default values for every option accepted by the inner component, like this.
1 2 3 4 5 6 7 8
This requires a lot of intimate knowledge of the internals of the inner component. You need to know all options along with their values and update them if they change.
This can however be addressed in a more robust way by the creator of the inner component by defining
the default values in a way that don't get overridden by
undefined values.
This can be done with a
defaultTo computed property macro in a very clean way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
With this little macro people wrapping your component can carelessly forward all options to the it with the peace of mind that default values are safe even if the user doesn't fill all the blanks.
There is still two downsides with this idea.
The first one is that this is preventing the user to pass
undefined to override a default value. I'd
argue that this is not a big problem because usually
null can be used for the same purpose, although I
imagine there is some edge case where
undefined is a perfectly valid value. I just haven't found one yet.
The second is that while it saves the component composing yours from having to know every default value, it still requires it to specify forward every option in the template. Not yet ideal, but at least you removed one half of the problem.
I hope some new HTMLBars/glimmer construction in the future, like the spread operator mentioned in some RFCs will improve the ergonomics of this.
Stay tuned for part 2.]]>
While it's true that most ember devs have started using them, I've seen that many people haven't fully grasped all its potential and the new patterns they enable, so I want to explain them a bit more, starting from the basics and going towards more advanced patterns.
First things first, let's see a few actions in the wild.
Which ones of these are closure actions?
1 2 3 4
If you said 2nd and 3rd you guessed right.
The 4th example is clearly just a regular attribute passing. It is named
action but could be named
and would be exactly the same, just a string.
The 1st line is a bit more fuzzy. That line is telling Ember to invoke the "sayHi" action when the button is clicked. Why doesn't it qualify as a closure action?
We have to start by explaining that the
action helper is overloaded and, depending on which context it is used in,
it does entirely different things.
action in the "element space"
When invoked within the context of an html element (what is known as the "element's space"),
action keyword does a quite a lot of stuff.
It registers in the global Ember dispatcher one (or some) handlers for events whose target is the element in
which it was invoked.
In the first line of the previous example, the helper is registering in the event handler for the
attached automatically by Ember to the root of your app, a handler that will be invoked when
the target of the event is that button. It's also doing the same thing for the
keypress event when
the pressed key is enter. That handler, in turn, will call the
sayHi action on the context of that template.
Apart from all that, the action helper will call
preventDefault() on that event, hijacking its default
behavior, like by example submitting the form in which that button lives. However, that will not
prevent the event from bubbling.
Both behaviors can be tuned from the template with options:
By default the
action helper registers for DOM click events but you can specify a different event name:
As we see, there is quite a process involved here, but this is not a closure action.
action as a closure creator
On the other hand, the second usage of this helper is as closure creator. This is the behavior the helper has in any other situation different than the one described above.
It does something much simpler but also much more powerful. It creates a function with a closure that invokes another function
That's it. You can think about it almost like this snippet:
1 2 3
Note: This is an oversimplification. Closure actions don't even use
Function#bind at all, but it's close enough to grasp the basics.
It does nothing else. It doesn't register any event handler, doesn't prevent default or stop bubbling. It just binds the given function to the current context and arguments. When provided with a string it will assume that it's the name of an action and will extract it from the current context.
So, if it is such a simple helper, why is it so cool?
Converting your actions to functions you can pass around has many advantages.
This one is often understated.
A function is a value.
{{my-component foo=bar}}
in a template means that we're passing to the component a property named
"foo" whose value is the value in
bar. What if
is a function? Nothing: it's the same idea. We're just passing a value.
What if we do
{{yield (action "submit")? Same thing, we're just yielding a value that happens
to be a function. That is all.
On this usage,
{{action "foo"}} is a helper and as such, tries to do its work as soon as the
template is rendered. If the current context doesn't have a function named
foo it will fail right away,
unlike element's space usage where it will fail at runtime when that event is fired and, oh surprise,
there is no action named
It still surprises me how many refactoring bugs this simple feature has caught for me.
Functions have return values. Closure actions are functions. Therefore modus ponendo ponens, closure actions have return values too.
If the component calls
this.get("foo")("someArg"), it is just invoking a function and will have access
to its return value, if any. This enables bidirectional communication with the parent context.
As a real world example, an
{{async-button action=(action "submit")}} will invoke the action and that
action can return a promise. Thanks to having access to that promise, the button can then change to a "loading"
state while that returned promise is pending.
Actions can be passed down/up as many levels as desired.
When passing actions as just strings with their names to be invoked with the
sendAction(actionName) in the receiver
component, each call to
sendAction will only reach the closest component in the hierarchy.
This means that when the logic to be executed lives a few layers up from where the event that triggers it
is fired, each one of the intermediate components has to define an action to capture and re-thorw the
call to the next level.
That is a lot of coupling.
Closure actions just being functions bound to a given scope means that they can just be passed as simple
values from the root to the leaves. Then, the last component in the chain can invoke that action with
this.get("functionName")() and it will be executed with the provided arguments in the correct
scope, releasing intermediate nodes in the chain of the burden of capture-and-rethrow actions by its name.
When we attach a closure action to an event handler like this:
Ember.js is just doing
That means that, as with all event handlers attached to DOM elements, it is invoked with the
as first argument. But since the handler function already has one argument bound, the event is received
as the second argument instead.
There is little-to-no magic happening here, just regular javascript.
That also means that is up to the user to call preventDefault or stopPropagation on the received event.
Tipically when using the
action helper you will pass a string containing the name of some function
that lives in the
actions property of your component, like this:
<button onclick={{action "sayHi"}}></button>
But did you know that you can extract any function from your component by passed an unquoted reference?
1 2 3 4 5 6 7 8
This is useful by example if you want a component to execute some arbitrary logic that can be decided by its parent, and passed as an argument.
1 2 3 4 5
Now that you know that it's possible, I strongly discourage you to do this.
This enters the personal opinion realm but I feel that if we start extracting methods of components
to use them as actions, why do we have the
actions hash at all?
Instead, when I want to be able to customize from outside a component what an action will do, I define an action inside the component that just delegates all its logic to a method that can be passed in from the outside.
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5
The behavior is the same but reading the code of the component is crystal clear that
is intended to be passed from the outside. I find this approach self-documented and more idiomatic.
Taken from the wikipedia:
Currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions
Without deep diving into Haskell theory and monad madness, let me only explain how you can apply this technique for your own benefit with an example.
Having this declaration in the templates:
1 2 3 4 5 6 7
In the
sendWithAjax function of the top-most scope:
1 2 3 4 5
Because currying.
Each invocation of the
action helper created a new closure and bound the given
arguments to the function. The first invocation bound the
this to the current context and the
first arguments to the string
"/users/registration". The second invocation bound the data to the function.
Since the context and the first argument were already bound, that argument takes the 2nd position.
Last, but not least, that function is assigned to the
onclick property of that DOM element, and when
it's invoked the event is passed, occupying the last position in the arguments list.
Translated to javascript, it's more or less equivalent to:
1 2 3 4 5
Using currying each level can augment the action with some extra arguments, and that frees the last level of the chain of the responsibility of holding all the information needed to perform the action. Each piece of data can live in the level where it makes more sense, without leaking outside it.
The action helper accepts a set of key/value pairs as last argument. One special option you can use
is the
value option. This option holds a path, and the closure action will be invoked with the
value contained in that path on the first argument instead of the first argument.
The most common example of this is to extract some value out of the event.
1 2
But often people doesn't realize that it works with anything, not only events. Per example:
1 2
This is specially useful when combined with the next point.
mut helper
The Data Down - Actions Up approach to propagate state changes in an app advices us to not rely on two-way bindings for mutating state but on explicit function invocations. Consider the next code example:
1 2 3 4
1 2 3 4 5
Pretty common. Changing the selection invokes the
selectShipmentType action with one value, and that
action mutates some value. However, setting some state as result of some user interaction is so common
that there is a built-in way to avoid having to define such simple functions over and over: the
mut helper.
This helper creates a function that will set on some property the first argument it receives. The following code is equivalent.
1 2 3 4
This, in combination with the
value option, can save you the tedium of defining super simple functions
to extract some attribute from the first argument.
1 2
Remember that you can use this not only with events but with any object.
For example, if you want to have an instance of Ember Power Select bound to some queryParam, you can do this:
1 2 3
1 2 3 4 5 6 7 8
1 2 3 4 5
1 2 3 4
Selecting a teacher will pass that
Teacher model to the
onchange function. From that teacher
we extract only the
id with
value="id" which is passed to
(mut teacherId) as its first argument.
That updates the
teacherId property in the controller, that is bound to a queryParam in the URL,
tehen refreshing the model hook of the route.
Going forward the Ember 2.0 path, closure actions are one of the tools in your belt you're going to use more often.
Understanding them fully will allow you to squeeze them to your advantage and write simpler and more maintainable code.]]>
Let's start with the troublemaker code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
I'm not proud if this piece of code, but I took it from a blog post somewhere else that was explaining how to inject the current user in controller/routes/whatever using ember-simple-auth. If it worked for the author it should work for me and it did after a couple changes.
In a nutshell, that initializer is executed after ember-simple-auth has prepared the session and
its task is to register a service named
current-user (initially null) and inject it everywhere.
The rest of the code is the logic that takes care of updating the injected value service once I got the current user from my API.
It stopped the application's boot and tried to retrieve the user from the server before resuming the app. If the user was not logged in the boot process continues but it adds an observer in the session to fetch and replace the service once the session gets the user id.
I didn't expected to ever lay my eyes on this code again, but life had other plans.
I updated to ember 1.13 successfully, but then I updated ember-data the app suddenly stopped working.
Apart from some deprecation warnings about registering/injecting stuff using the container, the
problem with this initializer was that
lookup('store:main') suddenly was undefined. WAT?
I dug a bit and I discovered that in recent version of ember-data the initialization of the store was moved from a regular initializer to an instance initializer if you're on a version of ember that supports them (1.12+). And since instance initializers are executed after regular initializers the store wasn't available yet.
Ok, not a big deal, I'll convert this into an instance initializer. - An naive developer (Me)
The new initializers have a different signature. Instead of receiving the container and the application
they receive an
applicationInstance that gives access both to the registry and the container. I
changed the relevant lines to look like this and refreshed the browser
1 2 3 4 5 6 7 8 9 10 11 12 13
appInstance.deferReadiness is not a function - Mr. Chrome
I inspected the object and dove into the deep internet to confirm the bitter truth. You can't defer \
the readiness of the application from an instance initializer.
Why would whoever did this remove that feature? Most of my app needs access to the current user in order to work!
And that it's not the only problem. You no longer can inject
null as a service.
Ok, I inject an empty object later my observer will swap them.
Again, nope. Ember now doesn't allow to register something under the same name once the application has started.
Ok, initializers are not useful anymore. Thanks for nothing!
I was starting to feel angry. I tried then to create an autonomous service that takes care of all the login. I can't show you the exact code because I never commited it but looked similar to this.
1 2 3 4 5 6 7 8 9 10 11
My idea was: If my service is a
PromiseProxyObject and its content is also another
I should be able to access the user though a double proxied interface.
I thought I had been very clever. It was self contained and clear and it worked! ….ish.
It only worked if you already had a session, but not if you try to login.
When you're not logged the content of this PromiseProxyObject is undefined. I was planning to set
the content to the current user in my login action and remove it when I log out, but what I didn't
know was that
PromiseProxyObjects doesn't support to change content after creation (and makes
sense, since it has to behave like a promise and promises can't change its status once it's settled).
Time to take a break and look at the problem with a different light. I had a tea while cursing stability without stagnation and went to Ember London's slack channel to share my dispair.
I exposed the problem in the general and @nikz told me that when he faced the same problem he
ended up creating a service
current-user that had an
instance property that is populated from
the application route.
That approach was a bit more manual but I was ok with that, the only thing that I didn't like was that
the public api of this approach was something like
currentUser.instance.isTeacher. It doesn't feel
natural to have to call
.instance and my app already had the assumption than the current user was a user
all over the place.
The inpiration came in that exact moment from combine my previous failed approach with this one.
What if my service is just an
Ember.ObjectProxy that proxies an inner user record? That way
the service is aways there, I don't have to swap it when the user logs in. Instead I just set its
content. Ember won't compain and I can continue to use
currentUser as if a it was a real user model.
The final code is very short and the public API remained exactly like it wanted.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
When I started this refactor I was annoyed because of ember's design decision, but looking back on the final result I find that once more not fighting the frameworks tends to reward you with simpler and better abstractions.
I find this new approach less magical (no hidden observers), with less metaprogramming (I not longer have to reopen the Session class) while mantaining the same nice public API I had before.
As a final gift for my efforts on this refactor I discovered a very nice advantage of this approach.
Stopping the application's boot process with
deferReadiness() until I have the current user before
continuing did not provide any feedback to the user, just a white screen of death, while with the new
approach the
loading.hbs template renders as is does with any other promise returned from
beforeModel/model/afterModel hooks.
Even if the start time is the same, the user has the feedback that the app is working as expected faster.
I hope this helps anyone else using ember-simple-auth/torii to update to ride the stable wave and get rid of all those deprecation warnings before Ember 2.0 cames out.
Initializers have changed a bit since this post has been published. Now the instance initializer should looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
I had the great luck of have participated in the creation of a some very successful projects that made me have some tough moments trying to meet the scalability demands. I am very grateful for that because those are the projects that really push your limits forward as a developer.
Nowadays creating a service will almost always mean creating a backend API consumed by one or many frontend applications, web or mobile, so scaling a service is all about scaling its API.
If you foreseen tens of millions of users, you need to design your API carefully, and I learned some of this things the hard way.
That's the the biggest truth about scaling.
I don't care how much love love you have put in writing that service in Go or how you have optimized your database, the most slow and bloated language/framework combination with the proper caching in place will outperform your super-efficient implementation by an order of magnitude.
No matter how fast your app works, it will be slower than a slow app not doing anything at all, so you must design your API with cacheability in mind.
When you design a piece of software you put boundaries around parts of your code that you don't want to pollute (logically speaking) other parts of your code, and you name that concept encapsulation. Proper encapsulation is the main selling point of that little thing called OOP.
In APIs you do the same, but when performance is a concern, you must take into account that not only the elements of your API influence its design. How those elements will be consumed is at least as important as the elements itself, and expose them in a scalable way must be another requirement. And polluting can also happen between the private/public boundaries.
Imagine that you are designing a system for a car parts provider. Your system will most likely have
/parts endpoint. This endpoint is consulted all the time by mechanics to check for compatibility,
characteristics and sometimes price, so you add a
price entry to your payload.
But not all clients get the same price because some got from you a better deal. You don't want the others to find out this, so that field is calculated by in request based on the user that made the request.
Congratulations, you're doomed. No caching for you.
Another common example of this is when an endpoint like
/users/123 conditionally returns the private
information of that used depending if you are that user or not.
This is an example of pollution as a consecuence of poor encapsulation. Your otherwise static and easy cacheable API has been poisoned by one single dynamic field, and even worse, one you don't even need most of the time.
There is for me two golden rules in API design:
Make your payloads homogeneous. Two different users requesting the same resource should get an identical representation of it.
Minimize the number of moving parts. A good API is that one that is mostly static and do not vary depending on the identity of the consumer. You can call this also objective/subjective. If you are mixing static & objective fields with variable & subjective ones in the same endpoint, specially if the variable information is not always required, you will have a bad time. Intead you should consider slicing your app into two separated static/variable endpoints.
The paradigmatic case of this pattern is getting the profile information of a user. Imagine an app where some information of the users is public (username, avatar, etc…) and other fields are private (email, facebook, money in the current account…).
/user endpoint will receive millions of requests per day. Searching users, displaying the author
of a publication, and many more, most of them from people that shouldn't know my personal phone number.
Only occasionally you want to display the private information to the user itself and maybe it's close friends.
You can be sure that walk the social graph of a user to determine if I can see the private information on each request is an absolute performance killer.
I found slicing the
user resource into
user and
user_private_info a pattern that has proven itself
very useful over and over, and I've enjoyed how ember-data async relations makes implementing this a breeze.
1 2 3 4 5 6 7 8 9 10 11 12
The encapsulation rule is simple: If you have any reason to consider some field private, it lives
in the
UserPrivateInfo model. Otherwise, it belongs to the
User model.
Now you can fetch it in a dedicated endpoint, but since the relationship is asynchronous the private
information will only be fetched when its really necessary.
Any user without permission trying to the the private information will get a 403. That shouldn't occur anyway because your fronted won't try to access the private information if your are not allowed, but you're safe if that happens.
Taking this approach, the payloads of the different endpoints will look like this:
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7
You might have noticed that the
id of the user and its private info are the same, so you might think
that I don't really need that field, but that would be leaking an implementation detail into your
business logic. It turns out that I have all the information in the same user table and therefore the ID
is the same, but I could change my mind and store that info in a different table with different ids,
and the same API is still valid.
Also, note that now
users API is objective. I don't need to perform an any kind of check to see the
requester and that user are friends. In fact depending on the business logic you might not even need to
be logged to access this resource. This allows to cache this endpoint at a very high level, using Varnish
by example, and don't even touch our servers.
Simple answer is: You don't
If you have been paying attention you have noticed that this API slicing is more based in the usage of the API than in the limits of the business logic itself. Conceptually speaking an user has both public and private information, but it is still only one business object, so the moment will come when you need to perform a save operation that affects information of both the public and private areas.
It would be massively complicated to synchronize save operations to two endpoints at the same time, so
I take the approach of using
user endpoint as single point of entry for write operations on the user
model, and send the private information embedded in the user data.
PUT request to update the user's profile has this payload:
1 2 3 4 5 6 7 8 9 10 11
create action in the user endpoint will take care of update both the public and private
information, return the user and also sideload the private info with it.
1 2 3 4 5 6 7 8 9 10 11 12 13
Wrapping up this approach, you have:
A public
/users/:id endpoint highly cacheable, maybe even a candidate to perform HTTP caching.
A read-only
/user_private_info/:id endpoint to get the the private information of the users. This endpoint
happens to encapsulate information that is variable, not usually needed, and would otherwise prevent the previous
endpoint to benefit from caching.
A write
/users/:id endpoint that accepts to receive both public and private info and updated both
in a transactional fashion.
So we have a
User model that when it's loaded from the API received the id of its associated private info,
but when saved carries that record embedded.
I thought I would have to implement some kind of custom serializer myself, but the I discovered that
DS.EmbeddedRecordsMixin accept a very useful configuration object.
1 2 3 4 5 6 7 8 9 10 11
That's all I needed to implement this functionality.
When this record is deserialized coming from the server it will contain the only id but when it's serialized for being sent to the server the payload will have embedded the user private information, just like the previous examples. My hands bled of how much I clapped.
I really think that Ember Data and json-api are not only useful tools, but also tools that make you a better programmer, and is amazing how much following it's conventions can help to get good software design.]]>
There isn't still much documentation out there about how to use it, this are my two cents: How to tamper requests/responses with service workers.
I was playing with service workers to add offline capabilities to a pet project of mine (mobile-patterns) and I wanted to return responses from cache when there is no connection available.
It was very easy. The offline cookbook that Jake Archibald put together has lots of good examples.
However, I wanted to let my app know that a response came from the cache instead of from the server. I am not sure if that is a good practice (time will make us more aware of what is a good idea and what is not), but I just wanted to do it, so I started inspecting the response and trying several ideas, but none of it worked as I expected, and that was because I was not understanding how Service Workers and Requests/Responses are designed.
I misundestood this until I read the spec and the article in MDN. Well, to be completely honest I haven't really read the spec cover to cover, but read some parts.
Service Workers is a low level API on purpose, so when we mangle responses we are playing with very low level objects. It turns out that the responses from the server are streams containinig binary data.
Streams can only be consumed once. That means that if you read the content of a response and then you forward that response to the browser, the browser will not be able to read it because it has already been consumed.
Every time you want to mangle a response and the return it, make a clone and mangle the clone instead
1 2 3 4 5 6 7
Once you have a service worker in place, all requests that your web performs will pass throught it. That means that any blocking code in your service worker will kill performance. For that reason, pretty much everything in the service workers API returns a Promise.
caches.match returns a promise that resolves to some cached response. Responses have a
text and
json methods, and all of them return a Promise.
You have to go asynchronous.
Reponses are read-only, so if you want to tamper a response, you need play with the content and return a new response instead, and the constructor of a response expects a Blob object.
In my example, I was receiving a JSON object and I wanted to add a key to the json. I knew that Blob existed, but I was not familiar with them.
This is the code that obtains a response from the cache, reads its JSON, adds some information to it and returns a new response with the modified content but respecting the original headers.
1 2 3 4 5 6 7 8 9
You can see a full example with comments here.
Start using Service Workers today!]]>
I've been working the last 6 months in The App Bussiness, which as you can imagine is a company fully dedicated to create mobile apps, for iOS and Android. During this time I've learnt a bit about the practices that make a UX a pleasure to use with your fingers. A lot of DOs and DONTs.
There is many curated resources to learn that, but I'd say that 99% are focused on native apps, and this is kind of sad. There is very few mobile web apps that really take advantage of touch gestures, but there is not technical reason for that.
We can build very nice touch UXs in HTML5, and Ember.js is as good as any other technology to help us manage the complexity of those interfaces, so I've made a tutorial of how to create the (probably) most widespead mobile UX pattern: The touch lateral slider menu:
Note: The first part of the screencast is also available in Spanish here, but translate the screencast seemed too much work, so the second part is only available in English.
Part I:
Part II:
The code is available here: https://github.com/cibernox/mobile-patterns. I case you want to collaborate, or you have an UX in mind you don't know how to implement using Ember, don't hesitate and open an issue/PR.]]>
This post is about why I really think that something big is happening right now in frontend development that is going to change the way we think about it.
That's what I think Ember CLI is about to do.
I've been using Ember.js a bit more than a year and a half, since some beta version before the new router saw the light, and I love it.
I won't listing all the reasons because of which I think Ember is great, but I'll mention one that quite ofter appears in the middle of other people's list and it deserves to be on top in my opinion.
The best asset that ember provides you is that it brings uniformity to your code.
Working in a very big ember app over a year with other 5 or 6 developers makes you realize that this unformity is not a small matter. Follow a set of conventions on your code is what makes the difference between working next to others and working with other people.
The rules and conventions ember enforces, no matter if you agree with all of them or not, make your code predictable. Everything has its place, and that is an incredible booster to your team's productivity. More than once I was in charge of making a change in a part of the code I wasn't even aware that it existed and I surprised myself being able to find the exact point where I had to make the change in a matter of minutes.
That is for me the greatest advantage of ember among other options. It doesn't just gives you the tools to do your job efficiently, it also gives you the guidelines and patterns to organize logically your logic in a way any other ember developer, even a new one, can understand.
It bring uniformity to the developer.
But there is still some missing parts on this.
Frontend development has traditionally been like the wild west. While modularity is a battle won long time ago in the backend word thanks to frameworks, package managers and patterns to share and reuse code, modularity is still coming to javascript in ES6. And package managers, like npm and bower are still relatively new and not completely widespread.
Develop an app is much more than add one feature after the other on a text file. You need structures, build tools, deploy mechanisms, tests, patterns… The average toolset of a frontend developer has expanded considerably in the last couple of years, and integrate a library on your project is not drop in a file and you're done. Not anymore.
That is just the reason why Ruby on Rails was such a disruptive revolution 10 years ago. It is not because it brought anything absolutely new to the dev world, but because it gave a place to each piece of your app in a way that all projects shared the same common foundation.
When that happened, suddenly share and reuse libraries, not among some of your own projects but with projects of people you don't even know, was simplified massively. Gems that extended rails with al sort of functionalities expanded like mushrooms in autumn. Authentication, logging, state managers, middlewares…you name it. All of them working out-of-the-box with rails, with maybe just a few config lines. Compared with all the time and effort that it used to require to integrate properly a 3rd party library in your [put-your-favourite-old-technology-here] project, that made of rails a game-changer in the industry.
Now I believe that ember-cli is about to achieve the same thing.
I can't avoid thinking about Ember CLI as "the missing parts" I mentioned earlier.
To the strong opinions that ember has about how you should organize your code logically, ember-cli adds the rules of how you must organize your code physically, including the folder structure and naming, along with a powerful and extensible build pipeline based on broccoli, package managers and a collection of wisely chosen tools and defaults.
In other terms, it brings uniformity to the machine.
It might not seem a big deal on itself, but that uniformity is what really makes a difference. I just allows libraries authors to know the foundation of the environment where its code will be plugged into.
If there is a word that summarizes the doors that ember-cli opens that would be extensibility.
That predefined structure along with its modular design, the package managers and an internal API providing extension hooks open the doors to share addons that just work™ with any app.
Ember CLI stands in the very same point that Rails did a decade ago.
I'll just illustrate a sample situations that prove the great change that this situation enables.
Is is a known fact that web components are a trendy thing. The next big thing according to many, because they allow you to just reuse among projects isolated bits of UI that solve common problems.
Imagine that you have to add a datepicker to a web app you're building. I'm sure you faced that problem before.
Since you don't want to reinvent the wheel, you surf the web an choose a cool web component to make your life easier, but it turns out that it's not so easy either. Maybe the component requires polymer.js. Almost certainly a datepicker will also require moment.js. Some specific versions. You have to include in your build pipeline the js file. And also the html template. And the base stylesheet too. All in the right order and after including its dependencies. And probably register the component/directive to use it from your templates. The documentation is pretty good (hopefully) and you will succeed, but it requires a lot of setup.
The standar architecture of Ember CLI allows authors that know their libraries better than you to wire up things automatically. The ember addon only requires you to install it
1 2
NOTE: Since version
0.1.5 of ember-cli, an addon can be installed with only one command.
You can replace this 2 lines by
ember install:addon ember-cli-cool-datepicker and it will
install the package from NPM and execute the corresponding generator.
and use it right away
And possibilities go far beyond this example.
Addons can modify your build process adding pre-processors (p.e. you can start using the new features of ES6 like classes and generators with ember-cli-esnext), register libraries, change the behaviour of the browser (ember-cli-content-security-policy), deploy automatically your app to S3 using redis as synchronization mechanism (ember-cli-depoy), add middlewares…
Imagination is the limit. And the angular (badum tsss) stone that enables all this possibilities is uniformity.
A couple days ago I published my first addon that allows any ember-cli app to use accounting.js with ES6 modules executing just a command. And creating it was a piece of cake.
That is a truly game-changer for me.
I can't imagine the frontend development following any path other than this. Share and reuse code like this is the way to go. I don't know how much will take to other competitor projects to have its own toolset as ember does, but I don't think they can remain on the sidelines much longer.
New times are coming. Better times I think.]]>
There is some documentation on the web about how to use bootstrap with ember-cli,
but I've found it to be outdated in general, since the syntax of the Brocfile.js
of ember-cli's projects has changes a lot in the last months, being now
app.import the swiss knife for almost everything.
Using bootstrap now is as simple as typing
bower install --save bootstrap and
adding this two lines to your brocfile:
1 2
The problem appears when you want to use the glyphicons fonts. Bootstraps expects
the fonts to be inside the
/fonts folder and nowhere else, so we can't just
import the font like we do with js or css files.
All docs I've seen about how to do this involve using broccoli plugins and the old syntax to move files within a tree, but that is not needed anymore.
app.import accepts a second argument which is an object to configure its
behaviour, including the output tree where we want a file to be placed.
Add this third sentence under the other two:
1 2 3
That's all. This also works with any other kind of file, like images or sourcemaps.]]>
The leitmotiv of the whole conference was, as its name suggest, the future of the javascript language and the web: new APIs, new programming paradigms, web components… everything that is fashionable in the web development world.
Today I want to talk about about web components and how they are for me, as concept, the most missed feature in the web since ever, not only because they are awesome on their own, but because they can push the web forward in new ways by helping us to support new features in new browsers and degrade gracefully in more crappy ones.
I've been a heavy user of Ember for a year now and I love how Ember's components can bring us the power of the newest features before thay are implementeda cross all browser, so this demo will leverage its advantages to conditionally display the best possible image format.
WebP is a new image format created by google (but opensource) that allows images with similar quality but with much lower weight. Since bandwidth is a valuable resource, specially for mobile devices, I want to use webp right now, but it turns out that at the time of writting that post, only Chrome and Opera support this image format. Neither firefox nor safari or IE.
There is a couple ways of acomplish that task on the server side.
One is by detecting in your nginx the images support of the browser by reading a header of the request, but I serve images from a CDN, so that solution is not for me.
The other one depends on your CDN provider. Some of them support that very same detection: when a
browser requests an image,
landscape.jpg by example, they will under the hood serve
to browser with support the webp image enmascarated with the same name.
I don't like this solution either because:
A) It forces you to have a webp version of every non-webp image, which is not always easy or even possible.
B) The worst one: IT LIES. The extension of the image says that is a JPG file but it isn't. If you save the image and try to open it with you OS image viewer, it will say that the image is damaged. For some uses it might not be a problem, but it doesn't feels right to me.
With ember components it's very easy to detect the support in the client side, then ask for one format or another, and also you can out-out of this behavior in a very easy way.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
That's it.
SmartImgComponent is an ember component that is used like this:
1 2
It receives the png/jpg version of the image and applying a simple rule, in my case just change the extension,
it outputs an
<img> tag with an src to the good url, and you can opt-out to this behaviour using
webp=false attribute.
The only trick I've done here has to do with the web support detection. Since is an async test, I need to pause the start up of the application until I know the support, and then I reopen the component prototype to add the proper flag and resume the application's start up.
Here is a jsbin showing this in practice: Smart Img Component
It's easy for me to imagine more use cases where ember components can be used to detect brower features and offer a well suited fallback when some browsers doesn't support the native thing yet.
You don't need to wait for the future. Implement it.]]>
|' + e + '' }); html += '
|' html += cell + '' html += '' }); html += '
|Victories' scoreboard.slice(2,scoreboard.length).forEach(function(e, index, ary){ var htmlClass = ''; var isMaxValue = Math.max.apply(null, ary) == e; if (isMaxValue){ htmlClass += 'fastest' } else { var isMinValue = Math.min.apply(null, ary) == e; if (isMinValue){ htmlClass += 'slowest'} } html += '
|'+e+'' }); html += '
|Total time' totalTime.slice(2,totalTime.length).forEach(function(e, index, ary){ var htmlClass = ''; var isMaxValue = Math.max.apply(null, ary) == e; if (isMaxValue){ htmlClass += 'slowest' } else { var isMinValue = Math.min.apply(null, ary) == e; if (isMinValue){ htmlClass += 'fastest'} } html += '
|'+e.toFixed(6)+'' }); html += '
A few days ago a the first preview version of ruby 2.1 was released.
It has many interesting improvements in the language, but the key ones are:
Some of this improvements are more exciting than others (thumbs up to frozen string, thumbs down to refinements), but as Yukuhiro Matsumoto said in his talk at the Baruco, which I attended, the main changes in this new release are internal, with the new generational garbage collector as the king of the party.
I don't want to repeat content on the web, Konstantin Haase already wrote a great article explaining all the new features. Check it out for more detailed information.
It promises better memory handling and lower GC runtime, which its suposed to lead to better overall performance.
I was curious about the numbers but I had not found any updated benchmark out there, so I run the benchmark myself to see it with my own eyes.
For that task, I used the popular ruby-benchmark-suite, which is quite old but has lots of tests and has become almost a standard.
The benchmark was run in my 2012 macbook air, with a core i7 2.0GHZ (2 physical core, 4 logical cores due to hyperthreading) and 8GB of ram. It takes about 25 minutes per implementation, just in case you want to run it too.
Just to clarify some details about how I performed the calculation in the bottom of the table, when I sumarize the victories I just count the victories of each implementation, so raising an exception is a failure, but when measuring the total time, if any of the implementations failed on that benchmark then its time is not computed in the total time of any implemetation.
These are the results of the three MRI implementations:
From this results we can say that, in general, ruby 2.1 is faster. It is the fastest implementation in more tests than 1.9 and 2.0 together, even considering that it fails in some benchmarks.
The total time taken by ruby 2.1 is also noticeable lower. Is about a 23% lower than 2.0 and a 27% lower whan 1.9.3.
As I see, the main reason of this huge diference is that some specific tasks, ruby 2.1 is several times faster than
previous implementations, by example in the
micro/bm_gc_array.rb benchmark there is a 500% performance gain.
Probably in real word examples the performance gain will be around 5%, which is anyway a significant improvement.
But it turns out that 2 days ago, while I was writting this post rubinius 2.0 was released.
Rubinius is by far my favourite alternative ruby implementation and I was excited about that anouncement. How will rubinius perform against the other implementations? And jruby?
I've run the same benchmark on
rbx-2.0.0 working in ruby 2.1 mode and also against
jruby 1.7.4 running on java 1.7.0_40-b43,
but in this case in ruby 2.0 mode.
All the cutting edge versions avaliable right now.
Wow!! I didn't expect that. Rubinius wins in twice as many tests as the second one (ruby 2.1) and also beats jruby in all the multithreaded tests.
Both, jruby and rubinius outperforms MRI's implementations by an order of magnitude when it comes to parallel processing, that was expected, but rubinius also doubles the performance on other math tasks. And jruby also performs very well, and probably would perform better in a computer with more than 2 cores.
Even if ruby 2.1 has the lower total time, this benchmark suite was written 4 years ago. The computer world have changed since then. Parallel computing is now the present, and I think that both rubinius and jruby have a brilliant future when it comes to scale our applications to the multi-core world we live now.
After some controversy yesterday, I've repeated the benchmark with some minor changes to make the bechmark more realistic. As always, is impossible to a syntetic benchmark like this to be trustworthy when it comes to reproduce the real performance that you will get in your applications.
I've updated the input size of many benchamarks that runned too fast (in less than a second) to make then more long living. Not in every test, because
sometimes it was not straightforward.
I also set the flag
JRUBY_OPTS=-X+C which forces jruby to use the JIT compiler even if the script is very simple.
First of all, notice that with the new input sizes some tests that did not fail in the first run failed in some implementations.
With the new benchmark the landscape changed a bit, but no so much. And the alternative implementations shine even more.
Rubinius still is the implementation that wins in more tests, but ruby 2.1 is not longer the second one. Now jruby has the honor. And also jruby wins an almost all the macro benchmarks, which are the most complex and generic ones.
On the other handle, ruby 2.1 still has the lower total time but jruby is just behind, very close. The diference of time between jruby and rubinius has increased so the longer tests and the JIT compiler favor jruby more than rbx.
I want to emphasize this because I feel that the more complex and long-living the applications are, the more advantage will the alternative implementations take from that situation.]]>
man command.
I was trying to debug an error in production. An ajax call was failing randomly (aparently) with a 500 but I couldn't figure out how to reproduce it, so my plan was to navigate around the page until I can understand what kind of parameters make the ajax call fail.
The fastest way to see that is look at the log.
The aplication has a pooling service that pollutes the log with a lot of requests that doesn't matter to me and makes impossible to find anything.
So I piped the output of the tail command to grep
Fail again. I see all the errors but I don't see the the context, so I can't know which action failed or what parameters made the request fail.
But unix always surprises me.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
There is many more options, but the important options here are
-B and
-C. With this options you can show the context around the matchings.
That command shows 2 lines before and 5 after the matching.
It worked like a charm!]]>
This a summary of the main 3 features o SASS, pointing out its differences.
Mixins are the most known feature of sass. They allow us to create a sort of functions to share similar styles among our selectors (well, sass also has functions, but I can't find a better word). The most evident use case is the mixins that apply vendor prefixes:
1 2 3 4 5 6 7 8 9 10 11
Mixins are the first feature that a sass beginner learns, but is surprising how often I see them used the wrong way.
By example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
Whats wrong with that? It's not DRY.
This is the generated output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
We see the exact same 6 lines repeated over and over in our css.
The golden rule of where a mixin is a good choice is just a few line above:
They allow us to […] share similar styles among our rules
The keyword here is similar.
A mixin is used to reuse rules, not values. In this case to create rounded borders of different radius, but if your ever find yourself writting a mixin that don't take arguments, you are doing it wrong.
@extends directive, on the other hand, is the static cousin of
It is designed for sharing rules and values between selectors while avoiding repetitions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
This time, the generated CSS looks like this:
1 2 3 4 5 6 7 8 9 10
It has just a fraction of the lines that the mixin approach, which is nice because lighter stylesheets means faster loading times, specially with slow connections (mobiles), and for the browser is also much more efficient to parse one single rule applied to several selectors than apply the same rule once for each selector.
This is awesome because thanks to
@extend we can have human-readable sass stylesheets (you know, split stylesheets in
several files, put together rules that apply to the same sections or components of the design, …) and at the
same time have machine-optimized css (all selectors that extend the same parent are chained in one single rule, no
matter in which file or how conceptually unrelated they are) and at the same time we can keep clean our html because
we don't need to add all over the markup classes like
.rounded-border or
.highlighted-text that have no
meaning from the point of view of the application's domain.
I know that some people disagree on what html classes are, but I am a big fan of use classes
to represent what that element means (
.user-avatar and
.selected-day by example) and not
how they must look (
.rounded-corners. and
.highlighted-text respectively)
After reading this you might wonder why if
@extend are so cool, is not so popular and used as mixins.
That's because
@extend can be dangerous.
The problem with this directive extending classes or id's, is that when that rules you are extending appears nested on the application, sass must generate all the posible combinations between the nesting classes and the rules that includes them.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
.button is a class that is very likely to be customized depending on its containing form, so if with
just 3 appearances generates this dissaster, with 10 appearances just let your imagination fly.
So the rule of thumb is: "Only extend a selector if you are absolutely sure that it is never reused in several places".
But the bad part is that you can't always be sure of this, and even if you are sure that at this moment you satisfy that rule, in the future, you or one of your coworkers can, inadvertently, screw things up.
Placeholders are an killer-feature added in sass 3.2, and they come to fix the mess I described before.
Unlike normal selectors, like
.classes or
#ids, placeholders won't be never compiled. In other words, this little piece of sass
1 2 3 4 5 6
will generate
There is no reference to
%button because placeholders are just named sets of styles meant to be extended by
other selectors, and don't have existence on its own.
Since they don't have existence on its own, they can't be nested, so you can use
@extend %placeholder-name with complete safety.
The previous messy example that used
@extend on a class could have been written using placeholders this way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
and you only get the rules you intended to get:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
After reading about the differences between mixins, extending classes and extending placeholders, these are some of the golden rules that I follow when writing stylesheets:
First of all, I have to recommend you to give it a try. A constant source of small pills filled with ruby wisdom. I've discovered many usefull tricks. It totally worths the 9$/month.
After my subscription, I wanted to download the old episodes (a few days ago Avdi published the 100th episode) but I didn't want to do it manually. I googled for a script but I didn't found any, so I decided to write one.
The problem I found was to download files from an HTTPS source that was behind a login form. My first
idea was to use a pure ruby solution like the
HTTParty gem, but after a few failed attemps I realized that
curl already has all that I need.
I've used curl with https a few times, but always with public documents, not with files that was behind an authentication form, but curl has built-in support for cookies.
To save a cookie you pass the -c option for specify the file where to save the cookie, and the -d option for pass a query string with the authentication params.
After that, you'll have the cookie saved in a file. Loading that cookie with the -b option you can download files behind the authetication process.
It works! It's time to write the script.
First of all we need to know how many episodes have been published and the files we want to download for each one. If only there was a place from where to obtain the basic information that is published in a compact and organized way! Oh, there is one. The RSS!
The rss can be easily obtained with a get request. It requires basic authentication, but doesn't need to set a cookie since there is no need to keep alive any session, so use your favorite http client. Mine is HTTParty, mainly because of its cool name.
The rss file is an XML file that can be parsed and inspected with nokogiri. Each episode in the rss looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<item></item> is an episode. Its title is inside a
<title></title> and the
<description></desctiption> contains some html
with one link for each file. The file's url is in the href attribute and the name in the text of the link.
That was all I needed to know. Here is the script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
You can find the code up to date in my github: https://github.com/cibernox/rubytapas_downloader
Happy hacking! ;)]]>
Is well known that Ruby is not a good language to build concurrent code. MRI, the main ruby interpreter, has a global lock that prevents any code to run in parallel. It is true that other implementations like JRuby and Rubinius don't have that global lock, but still there are not optimal for concurrency, because the language itself is not designed for it:
Ruby objects are mutable, so it has state. When the code is running in parallel, this may lead to strange behaviour and bugs due to unespected race conditions unless you are very carefull. And if you are too.
The basic data-types (arrays, strings, hashes) are not prepared for parallel read/write. To solve this problem there is a gem called hamster that provides a set of real inmutable structures, but still, is not part of the core.
The bast mayority of the libraries are not still thread safe.
In summary, people that are serious about concurrency tends to use real state-less programming languages. Functional programming shines with all its bright at this, and one of the most popular programming languages is Erlang.
Erlang was created in Ericsson in the late eigties and became opensource in the late nineties. Since then has grown in popularity for make easier to build fault-tolerant real-time applications. Is untyped, has garbage collection and works with message passing between processes. Today is more than a language, and has a virtual machine and a standar library focused in concurrency.
It powers some of the most scalable systems in the world. Probably the best example is Whatsapp, with millions and millions of messages by minute. You should see this talk of Rick Reed if you are curious about how they acomplished this magic.
For me the problem with Erlang is Erlang itself. I don't like it.
When I say that I don't like Erlang I mean that I don't like its syntax. Compared with the expresiviness of Ruby, Erlang is quite mathematical. This is not unexpected, all functional languages are. But since Erlang is also a runtime environment that executes bytecode, some other languages were build on top of this virtual machine on the same way that groovy or scala run on the java virtual machine.
Jose Valim, a ruby hero and well known programmer (simple_form, Devise…) created Elixir, a language that compiles to erlang bytecode with a cleaner syntax, clearly inspired by its ruby background, and day by day is gaining popularity because it makes more pleasant to build Erlang applications. Besides, it can cohexist with pure erlang and you can call any erlang function without any perfomance penalty.
If elixir is ruby, dynamo is rails. Actually, it is more similar to sinatra than to rails, but the important thing is that it holds the role of official web framework for the language.
It uses cowboy, a web server written in pure erlang, so it scales very well with relatively low resources and is concurrent by conception, on the same way that node.js is naturally evented and make is interesting to build certain kind of services.
You need to have erlang installed in your computer in order to install elixir. You can download the
latest erlang environment from here,
and then proceed to install elixir. I installed it in maxOS with homebrew (
brew install elixir).
The official guide has this topic covered for all operative systems.
Dynamo requires as well to have installed rebar for compile apps. Now you can clone elixir repository to create your first app.
Let's build a simple web app. The idea is that I have some fairy tales in .txt files and I want to create a web service that sends the story to N browsers in chunks, line by line, with one second between them. I want to have lots of opened connections for a long period of time without bloking new incoming connections and without make polling from the client side.
To create your first app and get dependencies:
1 2 3 4 5 6 7 8 9 10 11 12
You can go to that url to check that everithing is ok till now.
As with sinatra, dynamo has 2 basic components, the routers, under
web/routers and the views, under
From the controller you tell the connection to render one of the avaliable templates.
This is how the main router may look like in order to render the
index.html.eex template in the root path:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
and the template:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
The extension
.eex is like the
.erb for ruby, and the code is also evaluated with
<%= ... %> or
<% ... %>.
The static content, like the favicon.ico or the stylesheets/javascript files are served from the
/priv/static folder
but in the
/static/name-of-my-asset.css route.
I have 3 fairy tales, Snow white, Red riding and cinderella stored in tree .txt files in the root folder of the application. I want a page for each of this stories available under the "/name-of-the-tale" path.
If you have used sinatra or padrino, dynamo handles routing on a very similar way, so you only needs to enroute that url to a new action
1 2 3 4 5 6 7 8 9 10
and create the views
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
You have noticed that the variable we assign to the connection with
conn = conn.assign :title, normalized_title
are can be accessed in the templates as
@title. It also can seem weird that all the time you are
overwritting the same variable
conn over and over. This is because in elixir all objects are inmutable.
You can't modify the current connection to assign a variable to it. Instead of this, a new connection object
is returned every time you modify it.
This view can be DRYed using layouts, of course, but is ok for now. This view has a link to /play/name-of-the-story, the action that will send the chunked content.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
With this code I set the response header to text/event-stream because we want to use some javascript
in the client side to listen to the new chunks without polling.
conn.set_chunked(200) returns a new connection prepared to send chunks, with transfer-encoding: chunked
and connection: keep-alive.
conn.chunk "message" call sends a chunk the given message and returns a tuple, that can be
{ :ok, conn } or
{ :error, failure }. Assigning the tuple to
{ :ok, conn } saves the connection and
will raise an error if the first element of the tuple is no
:ok, which means that something went wrong.
Now let's test out code. The curl command is perfec for this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Aparently it works! Now lets do some javascript.
1 2 3 4 5 6 7 8 9 10 11 12
I catch the click on the "Play" link and create an event source that receives the chunks from the server. Each time a chunk is received it is appended in a reserved area with some fancy animations.
Let's test it in the browser:
Cool, ah?
I encourage you to play with both, elixir and dynamo. Is maybe more suitable for concurrency newbies (as I am) than stand alone elixir, and allows your to build read things in a snap.
You can find the application in my github. Fork it!]]>
Never again using merge strategies.
If you, being in the branch master, run
git merge -Xtheirs experimental_feature the conflics will
be automatically resolved taking the changes from the experimental_feature branch.
The opposite,
git merge -Xours experimental_feature, will keep the code from the current branch.
-s recursive forces the merging strategy to the recursive mode, which is the only strategy that
accepts the theirs and ours options. I did not know there where different strategies for
merge branches, but there are several. This is the default strategy when pulling or mergin one
branch into another, so most of the time won't have to specify this but is good to know. (did you even
know that you can merge more than two branches at once?)
Hope it helps.
Happy merging.]]>
This is a must have. Have your own domain is cool. If you don't like the .github.io at the end of the address bar, you can point your domain to github.
CNAME in the root of your repository with the nude name of domain. With nude I mean
www. of
* Configure the DNS in your domain control panel. Make the root domain (the @) point to
184.108.40.206, which is
github's IP, and the www subdomain to
your-username.github.com. Screenshot from my namecheap configuration.
And wait the dns changes to propagate. For me it took less than 15 minutes but can take much longer.
The main part of your blog are the posts but with octopress you can create any page or section that makes sense to you. Some ideas: Host the documentation/demo of one of your opensource proyects, an about-me section, a portfolio…
The pages can be places anywhere in the /source folder, but there is 2 main aproaches.
rake new_page[about-me]
rake new_page[about-me.html]
Creating this page is more or less like build an static html side with some simple suport for layouts and partials. The first lines of each page have some comments to configure which layout you want, enable or disable the footer and more.
Octopress is the essence of a blog generator. It only server static content, so it don't provides you an admin area to record and see the trafic and see the stats. This is not a big deal since google analytics is the most powerfull tool you can desire in this area, and octopress has built-in support for it out of the box.
Create a free acount if you don't have one, and add a New account for your blog. During this process you will get an ID number like AB-12345678-9.
Go and edit your the config file and add this id to the google analytics key.
1 2 3 4 5 6
First of all, I need to say that I am NOT a fan of SEO. In fact, for me is the biggest lie of the modern times, but still there is a few good practices that you should follow to help google to do its job.
You should add keywords for your blog and for every post you create. This keywords will help google to know for what searches your content can be a good result, so pick the words wisely. Think about the words you would type in google to find your own article, but pick just half a docen.
By example, the previous post could have these keywords: tutorial,create,octopress,2.1,host,github pages,deploy
The description is also important for google, since it's the phase that will show under the link when this blog post is listed as a search result.
You can these information in the comments section at the beginning of each .markdown file, like the posts.
1 2 3 4 5 6 7 8 9
The keywords and the description will be added automatically to the
<head> tag.
But there is still a things that can be improved. At the time of writting this, the description was missing in the posts, and there is no keywords for the blog level. A few lines fixed that problem.
1 2 3 4 5 6 7 8 9 10 11 12 13
The general keywords and description for your blog should be placed in _config.yml
Don't forget to add a category (or categories) for each post. Users will be able to find related posts and google will apreciate also this information.]]>
Straight-forward definition taken directy from the Github's repository description.
Jekyll is a blog-aware, static site generator in Ruby
What does that means? The concept of Jekyll is a bit different from the usual blog engine you might be used to see arround (read: Wordpress).
The tipical blog engine is some kind of web app that integrates administration tools, 3rd party plugins, WYSIWYG editor, login system, automatic draft saving, flux condenser… and also serves your static posts. As you see, most of the features a blog platform provides are not part of a real blog's raison d'etre, which is to publish content to the world and allow the world to reach that content. Jekyll gets rid of all these non-esential features. Is just a blog generator.
The keyword here is generator. Jekyll don't serves your blog, it only generates the blog as a bunch of static pages. No content is built at runtime, the html is created at complilation time. This makes the blog super-simple and blazing fast from the outside. No server processing, your blog is prebuilt.
What we loss in exchange? Well, almost everything else. You don't have an admin area, you don't have
an online editor, but hey!
We are programmers.
Of course, this means that Jekyll is not for everybody. Is built for people that is familiar with the development process and wants to have full control over the process. Each blog posts is placed in a markdown file (it can also be textile of just plain HTML if your prefer) following some naming and directory structure conventions, and then compiled into the final html structure that will be accessible from the outside.
Writing, styling, compiling and adding javascripts is up to you, and now is where Octopress comes into the scene.
Octopress is blogging framework built on top of Jekyll. It extends Jekyll in several ways, but the main ones are:
For this tutorial I'll be using the latest code direclty from the master branch and ruby 2.0.
The fist step is to get octopress, cloning the repo and give it the name you want for your blog.
You'll see that octopress has a
.rbenv-version file in the root folder that specify ruby 1.9.3-p194 as the desired version.
Maybe you want to update that file to the fresh ruby
2.0.0-p0 as I did. It's totally compatible. Living on the edge.
Now you can install all dependencies with bundler and run our first rake task to install a theme.
1 2
rake install will install the default theme, but you can install any theme you like cloning the desired
theme into the
.themes folder and run the task with the name of the theme. By example, to install the fabric theme:
1 2 3 4
You can see a list with some available themes here but there is a lot more.
The next step is to configure the basics of your blog.
Current master branch (octopress 2.0) only has a single configuration file (
Let's fill only the minimum information.
1 2 3 4 5 6 7 8 9
Now we can create our first post. The naming convention is explained perfectly in the official documentation:
Blog posts must be stored in the source/_posts directory and named according to Jekyll's naming conventions:
Instead of generate the file manually, it's much easier to use the built-in rake task
rake new_post["Title of the post"]
This task creates a new post with the given title as long as some metadata used by octopress. This is the comments
of this very post.
1 2 3 4 5 6 7
And now, It's your turn. Write somethin interesting. Remember that each time you want to see the preview, you need to regenerate the
blog, but there is another rake task for this too, the
rake preview task regenerates the content watching for changes and
starts a small server in port 4000 to serve the blog.
Take a look also to
rake generate (generates the content in the /public folder manually) and
rake watch
(watch for changes into /source and /sass folders and generates the files automatically)
Github pages is an ideal host for this kind of blogs. It's free, fast, reliable and very very geek. In fact nowardays it has become the most accurate and widespread resume for coders, and so, github pages can be the best way to introduce yourself.
To publish your blog in github pages, the first step is to create a github pages repository. It's really simple, and you can find the instructions here: Creating Pages with the automatic generator
Once you have finished this steps, you'll have a repository named as
your-username.github.io, almost empty. You want to deploy your first article to
that empty repository, but you before that you should know how github pages work.
Github pages expect to have two branches, the source branch and the master branch.
The master branch is the one that github pages will show. The changes in the source branch won't be published
until you push your changes to master. A very simple workflow we use very often while coding, applied to publishing.
You can configure those branchs manually and add your github pages repository as a remote, but there is also a rake
task that does all for you:
rake setup_github_pages[repo].
In the case of this blog, I ran
rake setup_github_pages[email@example.com:cibernox/cibernox.github.io.git] and the
rake deploy to upload the blog. In a snap the blog will be accessible in the url **http://your-username.github.io**.
Remember that
rake deploy just generates the blog a push to the master branch. Your source branch won't be
uploaded to github if you don't want to. You probably want, to have a secure backup online, among other reason. Commit your
changes and do
git push origin source.
I've found a problem running the rake task that setups for github pages. If you have a CNAME file to specify the domain of your blog, the rake task will make some weird assumptions about naming that make the task fail. So, if you plan to redirect your domain to github pages, add the CNAME file after running this task.
Now your blog is online, so what's next? These are only advices, but you may be interested in perform some of this tasks.
In the next article I'll be covering those topics. Stay tuned.]]>
Some time ago I had another blog called "masquerailes", where I wrote half a docen posts about development, specially about ruby, in Spanish. Lots of things happened, now I live in another city in the other side of the country and changed my job twice, but at the end my calling remains untouch.
I love coding. I feel very fortunate for have made of my hobby a way of living. But life has a lot of facets, and even if I love to make experiments and research on coding topics, I also had lots of things that drawn my attention enough to stop writting my old blog. That are not bad things, build a family and have other hobbies are always a good thing to have, but I've realized I miss to spend more time being creative.
At work most people can't be as creative as they would like, because the real work is always there, waiting to be done, and deadline exist. When you have milestones to reach and deadlines to respect, you tend to follow the path you know better, even when if you would like to try some new tools or patterns that could fit better.
That's why I write this blog.
I want to force myself to push my limits, to exit my confort zone and write about topics I know well and want to know better (by sharing with the world a small portion of what I gathered from it) and to make me research on topics I would like to know more. And incidentally, to practice my English.
So my first blog post will be about creating your own blog using Jekyll and Octopress and host it for free in github pages. This one you are reading right now :)
See you soon.]]>


text:
Dan Post Gel-Flex Cowboy Certified Caiman Stockman Boots BOOTS DP2806
Dan Post caiman alligator boots for the true cowboy! This exotic cowboy boot features a fancy stitched 11" distressed leather shaft over an impressively tiled, flank cut caiman skin foot. Leather lining. Vented Poron anti-microbial insole. Double stitched 3/4 welt. Solid brass sole nails. Updated broad square toe profile. Low 1 1/4" stockman heel.
EW, Extra Wide, equals EE width.
- Cowboy Certified leather & TPU rubber sole for comfort & traction; eases in & out of stirrups
- Western spur ridge
- Genuine flank cut chocolate caiman alligator skin
- High impact Gel-Flex insole
- Dan Post Cowboy Certified boots offer modern good looks & real cowboy comfort.
- Shank stabilizer for extra support
- Online Only

subset: commoncrawl


text:
Fashion Workwear/Excel Sports store is the point of sale for RUSC players' uniform. RUSC will issue uniforms only for players from U4 to U6. All other players who require replacement garments will be required to go to Fashion Workwear to purchase them. All players are required to wear and purchase the jersey style and colour as specified by RUSC.
The safety of RUSC players, coaches, team administrators and spectators is a primary concern
during all matches. Highlights of this policy are: soccer related injury, return to play and accident preventions such as field inspection, lightening safety, inclement weather safety, high humidex safety and insurance and procedure. Included in this Policy is a link to the Club's Concussion Protocol.
RUSC Soccer, Registrations and Fees


text:
ST. GEORGE — After a naked man allegedly kicked down the front door of a home in a rural part of Iron County Tuesday, the homeowners shot him multiple times before he left and was arrested.
Christian Holbert, 24, from Washington County, is accused of breaking into the home on 17800 W in what is known as Old Irontown in southern Iron County at about 12:40 p.m. Two elderly residents were in the house when Holbert broke in, according to a press release from the Iron County Sheriff's Office.
"The homeowners felt threatened by the male and his demeanor and as a result, the suspect was shot multiple times with a handgun," according to the press release.
After being shot, Holbert was still trying to get up, was not listening to the homeowners and was being "irrational." He then left the house and was found by officers about 20 minutes later. He was still naked and being noncompliant when police arrived, so they used a stun gun on him multiple times, which "had little to no impact on Holbert."
Deputies were eventually able to subdue the man and arrest him. Emergency responders treated Holbert's gunshot wounds at the scene and transported him to Dixie Regional Medical Center via Intermountain Life Flight helicopter. His injuries are serious, but probably not life-threatening, said Lt. Del Schlosser, of the Iron County Sheriff's Office.
Drugs are believed to have caused Holbert to be acting the way that he did, Schlosser said. Charges are pending and will be filed after the investigation is completed.
There are no charges being filed against the homeowners at this time. They were uninjured but distressed from having to shoot a man in their home, Schlosser said.
"Obviously, they're pretty shaken up after being involved in such a dramatic event."
This report is based on statements from police and may not contain the full scope of findings. Persons arrested or charged are presumed innocent until found guilty in a court of law or as otherwise decided by a trier-of-fact.
Email: email@example.com
Twitter: @STGnews | @SpencerRicks
Copyright St. George News, SaintGeorgeUtah.com LLC, 2018, all rights reserved.


text:
Support Group Meetings
Please see our Philosophy and Code of conduct for support groups page under About us.
Location: Fifth floor at The Centre for Excellence - 50 Market Street, Melbourne (stop No. 3 on both Flinders Street and Collins street Trams)
Meeting Times 2019
January- there is no support group meeting.
2nd March
6th April
4th May
1st June
6th July
3rd August
7th September
5th October
2nd November
2pm - 4pm Support Group Meeting
2pm - 4pm Support Group meeting
1pm - 4pm Special Mothers Day Support Group Meeting
1pm - 3pm Support Group Meeting and start of our Winter timetable
1pm-3pm Support Group Meeting
1pm-3pm Support Group Meeting
2pm-4pm Support Group Meeting back to regular times
2pm-4pm Support Group Meeting
2pm-4pm Support Group Meeting
|7th December
1.30pm -4.30pm Annual General Meeting (AGM) This will be held at the address above
Geelong meetings will resume in February 2019
Geelong meetings will be held at South Barwon Community Centre, 33 Mt Pleasant Road, Belmont.
23rd February - 2pm - 4pm
25th May - 2pm - 4pm
24th August - 2pm -4pm
23rd November - 2pm - 4pm
Location: Traralgon neighbourhood learning house 11 Breed St, Traralgon.
16th March 1pm -3pm
15th June 1pm - 3pm
21st September 1pm - 3pm
21st December 1pm - 3pm
Location: Eastwood Leisure Centre 20 Eastwood Street, Ballarat
16th March
15th June
21st September
21st December
2pm - 4pm
2pm - 4pm
2pm - 4pm
Mildura meetings are being dicontinued due to ceasing of funding and lack of numbers. We are planning to skype distance members into our Melbourne support group meetings
|All regional members are invited to attend the Arms mothers day meeting and the AGM in Melbourne....details above
For women wanting to go to a support group outside of these centres, there are other meetings run by other organisations holding support groups at Bendigo and Albury/Wodonga.


text:
I am a chipmunk breeder and sell chipmunks in Bristol England United Kingdom... I have agouti (brown) females and male breeding colony... all have dilute (white) and agouti blood lines.
Contact Me
If you are interested in a baby chipmunk or have any other questions concerning chipmunks please feel free to leave a comment or to e mail me, email@example.com It is essential that you aquire appropriate housing for your chipmunk before adoption. Chipmunks need a large cage or an aviary so that they can run, climb and jump. They also need their own nesting box to sleep in and feel safe. If you have any further questions about housing... just ask :o)
You can find detailed pictures at the bottom of my blog that show how to determine the sex of your chipmunk(s)
You can find detailed pictures at the bottom of my blog that show how to determine the sex of your chipmunk(s)
Tuesday, January 20, 2009
some news
Hi again... well it seems that the little male has now matured and it looks very positive for a litter or two this spring... fingers crossed.
Posted by Madwag at 9:07 am 5 comments:
Subscribe to: Posts (Atom)