Posts tagged rails

Custom File Processing Forms in Active Admin


I needed to add a form to Active Admin so that a client could upload files, which would be parsed and the data added to the database. Here’s how I did it. In , register the relevant model with ActiveAdmin. In this case, the files contain information of users, which would be loaded into the database, so we park it under the User model. Then, we add an to the User panel, and associate that with a , which we use to render a form partial. We indicate the action in the form partial, which is added as below: This action can contain any arbitrary parsing application logic, the result of which can be displayed to the user in a flash notice, as demonstrated simply above. Also note that the file is not stored subsequently.

Single Table Inheritance in Rails


Single table inheritance (STI) in Rails allows you to store Ruby subclasses in the same database table. Let’s get started with a brand-new Rails project to learn what that means. I’ll be using Rails 4.2.3 and SQLite as the database. First, an empty User model: In : Generate a migration for it. To implement STI, we add a column called of type to the class. Let’s also have a name column: Migrate the SQLite database: Fire up the Rails console: Let’s create a new user: No problems so far. Now, let’s say we want to differentiate users between regular users and power users. At this juncture, let’s pretend we don’t know about STI. Since we’ve already created the column, let’s use that, so we can find different types of users by writing something like this: Go ahead and create such a user: Uh oh. What just happened? Why is Active Record complaining about not being a subclass of ? It turns out that Active Record, upon, seeing a column named , automatically assumes you’re implementing STI. Into Rails Down The Stack Let’s take a dive into the Rails source code to find out how Active Record automatically assumes this behaviour, by finding out step by step what happens when we attempt to type to create a new power user. The source code below is as of commit on the branch. Sean Griffin explains briefly in his comments in Active Record’s module. In : method in : We start our investigation from Active Record’s module, which contains the method definitions of some of the most-commonly used Active Record methods, such , , , and (protip: use in Sublime Text to search by method definition). We first check if the supplied argument is an array. If so, we recursively call for each member in the array. This means you can do something like: and Active Record will create three users, and even return them to you in the same array structure you specified: If we supply a hash, then the method is called: method in : Notice the splat operator, which converts all but the last argument into an : We take the first member of the array and run the method on it, which is located in the same file, some ways down: method in : This method checks through all of the attributes in the model to see if any of their names match the specified inheritance column, which in this case is . Therefore, returns . Let’s see where and come from. method in : where is: method in : I’m going to stop here because steps into whole new territory: namely, into the scary module…

Notes on "Rebuilding a Web Server"


Some notes I took while watching Rebuilding a Web Server, a brief walkthrough by Marc-André Cournoyer on writing a simple Rack-compliant web server. The code for the class is here. Concurrency The entire stack looks like this: There’s also a scheduler running alongside, handling concurrent connections. Such a scheduler can be implemented in different ways: threads, pre-forked processes, or an event loop. Threads A naive implementation would look like this, spawning a new thread for each incoming socket connection: Web servers like Puma use threads. Thread spawning is quite expensive, so web servers that use threads for concurrency will usually spawn a number of threads (thread pool) on bootup and reuse them. Pre-forked Processes Preforking is a popular concurrency model used by servers such as Unicorn and Nginx. creates a copy of the current process, and this child process is attached to its parent process. The two of them share the same socket. Worker processes are forked beforehand, and all of them share the same listening socket. Whichever process is free will be scheduled by the OS scheduler to handle the next incoming connection on the socket. Presumably, leveraging on the OS scheduler is really efficient. Event Loop We can simulate an event loop in Ruby using a gem called . is a feature-packed gem, and comes with helper methods that handle accepting, reading and writing to and from socket connections for us. is an instance method of the IO class in Ruby which allows us to read data off a socket as soon as data is available. The APIDock entry on elaborates further: readpartial is designed for streams such as , , , etc. It blocks only when no data immediately available. This means that it blocks only when following all conditions hold. the byte buffer in the IO object is empty. the content of the stream is empty. the stream is not reached to EOF. Using the method, we can read off a socket like this: is a method with similar functionality. is a gem that wraps around Node’s HTTP parser. Rack Rack is a set of specifications that web servers, middleware applications, and application frameworks must adhere to. Rack apps must have a single point of entry named , which must return an array containing the status code, the headers, and the body of the response. Things which behave exactly like Rack tells them to (e.g. Unicorn, Rails) are Rack-compliant, and the benefit of this is that Rack-compliant things can be used in conjunction, layered on top of…

Rails Boot Sequence (Part 1)


Today, we investigate Rails’ boot sequence by observing what happens when we run . Part 2 will look at . Github links to relevant files are provided as necessary. Our journey begins inside the binary, which is executed by : It calls , which corresponds to : In : is in charge of executing the inside your Rails application. It will look for it recursively, meaning that you can call anywhere in your application directory. In fact, or is equivalent to calling or See the abridged contents of below: Next, we turn our focus temporarily to your Rails application. In , two files are required: (in your app directory) determines the location of the Gemfile and allows Bundler to configure the load path for your Gemfile’s dependencies. parses options passed in as command line arguments, including alias mapping ( for , for , etc.) is in charge of throwing errors in the case of invalid commands, or delegating valid commands to the respective methods, themselves split into files in the directory: For example, if is run, the method in requires and runs the class method from the class, passing it your application as the first argument ( is made known of your application by requiring , which you’ve kindly provided previously in ): In , you can see the class method instantiating itself and calling the new instance’s instance method: As it is instantiated, is set as your Rails application, and is set to if present, or defaults to : Let’s see if the above code actually works by setting your application config to use as the console instead: Great success! Now let’s look at the actual instance method, whose code is relatively self-explanatory: Finally, boots the console. Next, we’ll look at the code path taken by . As indicated in the comments, this file is auto-generated by RubyGems. How does it know to load Rails, as in the last line ()? Taking a look in gives us the answer: What does the above mean? RubyGem’s documentation: Take a look inside the directory - its contents will be very familiar soon :) The binary is defined by the sha-bang to be executed by , which is a thin wrapper that allows RubyGems to run initialization hooks () before Ruby runs the actual code (). This is what the actual binary looks like: You can test this out for yourself with just 3 lines of code. Create a file with the following: Run it and see what happens: