Skip to main content

7 Open Source Vlog - Simple And Clean RubyGem With Rails Engines

Episode 73 · July 8, 2015

Rails Engines really make our code shine for simple_calendar

Open Source


Transcripts

What's up guys? Today we're going to be taking a look at how we can move this calendar from our rails app into our gem. We've created yesterday this really sweet balance between ruby and erb, and I'm actually really impressed with how that turned out, and if you're familiar with devise, which is one of my favorite gems that I use in almost every application, they have this fall back. Let's just hop on to their GitHub page. So basically devise, if you're not familiar with it, you can create a user model, it has a bunch of views for you to use, like sign up, sign in, forgot your password, edit your account. It does that out of the box really really easily, and if you dive into their code here you can see in their devise folder, that is all of the views that they provide. This is really cool because it allows you to install devise and not have any new views in your application, but they easily make it so that you can generate and install these into your application, and they'll basically copy all of these into your rails app so you can customize them, and it's wonderful, it's really really easy to use, and that I think is the balance that I want to strike with simple_calendar, so you want to use a month calendar, a week calendar before day agenda calendar out of the box? Great, you don't need to install any views into your rails app but if you want to customize those, I'll have you generate those and install them into your app, we'll make copies and then you're able to create your own calendars using that, and you'll be able to control that code without having to deal with all this magic inside of the gem. That should solve most of our problems. There's really the balance that I was hoping to strike, and I didn't realize we're going to basically just kind of copy devise when I started this, it turned out really really great. Let's take a look at what we've got. I've actually have this calendar application, the rails app that we created, and we made the views/meetings/_calendar.html.erb file yesterday. This is great, but we actually want to move this into our gem so that it shows up there by default and then you can basically render this or copy this into your rails app, and we'll render whichever exists first. Let's actually move this out into our gem.

mkdir -p app/views/simple_calendar

That should mean that in your rails app, when we install these, you would have an app/views/simple_calendar week calendar, month calendar html erb files, that would allow us to basically namespace all of our templates in your rails app in the simple_calendar folder which makes a lot of sense. It's exactly what devise does and it's definitely worth doing. So we'll make that and then we'll hop back over and finish our move, and here we can do

mv app/views/meetings/_calendar.html.erb ../simple_calendar/app/views/simple_calendar

That should be that, so I'm curious we moved the file into the gem, I'm curious what happens, I'm assuming that we're going to make a missing template and we do, and basically this says: We can't find the calendar template any more, and we're looking in these two directories. Right now it's looking for meetings/calendar in that folder, or application/calendar. Within the rails app it looks in those two folders. But you can also see that it searched in this one directory, so these are actually like our search paths, and we want to make a search path inside of our gem once it's installed, so we want to make sure that that gets added. I'm not quite sure how to do this, nor am I sure how devise does that, but I'm wondering if we can accomplish it by just setting up something simple, so let's open up the code for simple_calendar, and I can't remember, but I believe I did have a railtie, so I'm wondering in a railtie if we're able to add this directory in as the search path, and maybe we are, maybe we also want to try restarting our rails app and see if that affects anything, but I believe we have to kind of tell rails that that's a folder that we want to look for that in. Also there might be something important here that we need to say: simple_calendar/calendar because we've now put that in a separate folder. Let's open up the calendar file here, and we're looking for the simple_calendar partial this time

calendar.rb

def render(&block)
    view_context.render(
        partial: "simple_calendar/calendar",
        locals: {
            date_range: date_range,
            start_date: start_date
        })
end

Let's restart our rails app and try this once more. I'm just kind of experimenting because I'm not completely sure on how this works. I know that one thing with if you're creating a gem for a front end library, when you just add the railtie, all of the app/assets folder are automatically findable, so that one is really interesting, we really just need to add this into the template path, so let's look this up.

We need to have our gem append this to the application. I just did a little bit of digging, I didn't really find anything for like 15 minutes, I kind of cut that out because it wasn't very interesting, but it led me down this path that I don't know what I'm trying to search for, but I do remember that I set up this rails railstie, and this basically allowed me to say: Hey when rails loads, let's add configuration values in there so that we can do some stuff, and so this was like: We're going to set up an initializer, and then ActionView::Base should get the view helpers from my gem included in that, and that got me thinking there's this railstie and then there's this other thing called a rails engine, and engines are kind of like miniature rails apps inside of a gem, so you can put a mini rails app inside another rails app, and that got me thinking maybe we should find out the difference.

One of the things that's important to note is the difference there. The first thing kind of result you get on Stack Overflow is that a railtie can probably do what you described, it may be more desirable to use an engine. The engine can have it's own configuration and also acts like a rails application since it allows you to include the app directory with controllers views and models in the same manner as a regular rails app. That's really what we're trying to do here, we want our gem to have sort of the fall back, we're going to look first in your rails application for the calendar, and that would be if you overwrote ours, and then if you don't find anything, we'll go fall back to the gem and we'll use that template, so it's probably a rails engine that we want here, and if I remember right, I think we can look up on GoRails, to "Creating a gem for a front end library", I believe I created an engine in that case, and that is one of those things that was this special syntax or class that you just needed. It was an engine, and that was the key piece of why it wasn't working with our gem automatically because I set up a railtie not an engine, and the enginers loads differently and rails does different things with those. That's an interesting thing, I'm not familiar with these, but now I'm starting to get a better idea of the separation between them and I want to dive more into those in the future, it's kind of magical how easy that is to just define a class, so chances are we can just find a class called engine here and it inherits from rails engine, and it's empty, and I think this will work. It's kind of magical how that works, and I'm really impressed and also sort of disappointed because it's not clear what it does.

That's all we really needed, we just needed to add a rails engine into our application, that was wonderful. At the same time, it kind of sucks because we don't actually know what the heck it's doing, it's kind of just setting up all these default, but I'd love to have like a broken out list, like what really does an engine do, we can probably look that up in the rails docs, but I'll do that later. Right now we've accomplished exactly what we want, we've got the calendar loading from simple_calendar in the gem, and if we dive into our rails logs here we can see in the render lines here in the vlogs, this one rendered the meetings/index, but we can also see right above it before you could render the full index, you had to render out the calendar which comes from the gems path, which is so cool, that was as easy as it was to get this going. Now we can start probably tomorrow making the week calendar or the month calendar, making separate templates for those, and then after that we can run the generator so we can overrun these files, and I bet you if we go and copy that file that we just moved over, if we go grab app/views/simple_calendar/_calendar.html.erb,

mkdir app/views/simple_calendar
cp ../simple_calendar/app/views/simple_calendar/_calendar.html.erb app/views/simple_calendar

We can hop into the source code here and maybe we don't want the title or the dates or any of that to the next and previous ones, and I bet if we refresh it will load the local version, I mean we can double check in our rails logs, and if we look at this now, it doesn't say /users/chris/code/simple_calendar/gem all that stuff, now it does a relative path to the simple_calendar folder inside the app/views folder. This is working exactly how we expected it, it starts with the rails application that you're running, it looks in the app/views folders, tries to find a match, if it doesn't, it looks in the gems that we had included, and if they're an engine, it will check out their app/views folders, and then do a full render from a whole different directory which is super cool. This actually is working exactly as expected, this will be amazing for customizing it, because you'll be able to make your own views inside the simple_calendar folder, you probably won't have to do any magic with that, and that will be as simple as it is, you can have all the classes you want, you can customize this as much as you want and there really is not a whole lot of magic going through this. We're making some really really good progress and I love how this is turning out, I'm super impressed, I didn't know where are you going before we started the vlog, so that is really cool. Tomorrow let's make the month calendar happen, with a month calendar html erb file, see you then. Peace v

Transcript written by Miguel

Discussion