Rails and View Helper Methods

Tarot reading is the practice of utilizing tarot cards to gain an understanding of the past, present, and/or future. Typically, a question is asked, cards are drawn, then an interpretation of the cards is provided. Tarot card reading has been around since the late 1700’s and now, over 200 years later, has gained popularity.

connecTarot is a web application built with Rails. It is designed to connect like-minded people together in the world of tarot. Users are able to track their own tarot readings, receive readings, and conduct readings for others. This application was built with inspiration from my wife (who is deep in the world of tarot) as a portfolio project for Flatiron School.

Image for post
Image for post
The connecTarot root path implements a mystical user interface.

Features

There are five primary features of the application. The first is integrated user accounts with a standard sign-up method as well as the ability to sign-up with Facebook or Github. In order to implement this functionality, the following omniauth gems were utilized: gem 'omniauth', gem 'omniauth-github', and gem 'omniauth-facebook'. A dynamic route was implemented in the routes.rb file in order to have an efficient route for receiving information back from the provider:

match '/auth/:provider/callback', to: 'sessions#create', via: [:get, :post]

The User model has a class method that gets invoked when a user attempts to sign-up or login with the provided Facebook/Github links. This method utilizes the find_or_create_by method that ActiveRecord provides in order to cover scenarios in which the user is signing up or logging in.

Image for post
Image for post
The User class method assigns attributes only when the user’s email does not exist in the database.

The main feature of the app is the ability to create tarot readings for yourself with computer generated “shuffling” of a deck of tarot cards. Users have the option of selecting an existing spread of questions, or they can create their own spread by providing three questions they are seeking guidance on. The user will then be prompted to pull a card three times.

Image for post
Image for post
Creating a new reading is simple and fun!

There are 78 cards in a tarot deck and they are all seeded in the database. The .sample method is called on Card.all as a class method in order to randomly generate three cards (excluding duplicates) out of the computer generated “deck” of cards. After pulling three cards, the reading is then displayed. The reading includes images of the three cards pulled, along with the meanings of the cards displayed in the context of the questions that were asked (or part of the pre-made spreads).

Image for post
Image for post
Meanings for each card are stored in the database and are displayed when a reading is saved.

A unique feature is the ability to add thoughts to a finished reading. Reflecting on the cards drawn is an essential part of a tarot practice, so users can add thoughts and see them displayed below the reading.

Image for post
Image for post
Functionality to add thoughts to a reading is useful in the world of tarot.

The fourth major feature is the ability to track your readings over the course of a month. This feature is useful because it allows the user to gain insight into patterns that develop throughout each month. The monthly summary table shows your total readings, total cards pulled, major cards pulled, minor cards pulled, court cards pulled, and the number of cards pulled for each suit. It also displays specific cards if they were pulled more than two times in a month. Users can also filter all of their readings by a specific card or spread.

Image for post
Image for post
Users can track monthly patterns as all readings are saved to the database.

The final feature is the ability for users to request and respond to readings. Integrating a card’s meaning in the context of a specific reading is a major component of tarot. So in addition to the card meanings being displayed, other users will be able to write out an interpretation for the requestor based on what the requestor is seeking insight on. All users are able to view the requests index page. This is where all of the requests are shown, in order of the status of the request (open, pending, or fulfilled) and by descending date of creation.

Image for post
Image for post
All open, pending, and fulfilled requests are show on the requests index page.

Once another user responds to a request, they are provided a form on the request show page.

Image for post
Image for post
Responders will see the form to create a custom reading with interpretations for the requestor.

Once the form is successfully submitted, the requestor will have a new entry on their “My Readings” page. This entry will still display the meanings of the cards, but will also display the custom interpretation from the responder of the request.

Image for post
Image for post
The interpretations are written to and displayed on the requestor’s readings page.

Challenges

One issue I ran into when building this app was how to efficiently display the attributes of a reading in the show.html.erb view. When a custom reading is complete, the interpretations are displayed on the reading’s show page. Each reading (named entry in the app), has three optional attributes for interpretations. These attributes are named #interpretation_1, #interpretation_2, and #interpretation_3.

In this view, I implement an iteration to display information about the cards pulled, including the interpretations (if any exists):

Image for post
Image for post
This iteration displays card attributes, as well as entry interpretations, if they exist. By adding several helper methods, an iteration was able to be implemented which drastically reduced the number of lines of code.

The last line of code in this iteration invokes the helper method #display_interpretation_if_request_exists. This method (and iteration in general) was crucial for thinning out the lines of code needed to carry out this functionality. This method uses concatenation to execute and display multiple lines of generated HTML if entry.request exists (is true). This method calls another method, #display_entry_interpretation.

Image for post
Image for post
This helper method allows us to reduce the number of lines of code down to one line.

In this method I utilize the #send method. Since we are still in the iteration, I created this method so that I could call reader methods dynamically. For example, I wanted to display the #interpretation_2 attribute of this entry. So you could code it as @entry.interpretation_2, but I instead utilized these methods within the iteration to dynamically call the correct methods based on the index of the cards array. The #send method allows us to ‘send’ a block of code as a method. So I am sending the local variable inter as the argument for #send, and inter is a string that utilizes string interpolation to dynamically set the variable name for each cycle of the iteration.

Image for post
Image for post
This helper method within the first helper method allows us to dynamically change the method name that gets called.

Another issue I had was when I implemented functionality for a responder to create a reading for the requestor. The form for this request is shown in the requests/show.html.erb view file. This form sends a POST request to the user_entries_path. In order to make this function properly, I implemented an if statement in the entries#create action in which it looks for the existence of the value for params[:entry][:card_ids].

Image for post
Image for post
When a user pulls the first card, an entry is created as a POST request to the create action. Every card pulled afterward is a PATCH request to the update action.

The somewhat challenging part was authorization. I created a method called #require_authorization that gets executed as a before_action for all actions in the EntriesController except for the create action. This method checks if the current user who is logged in is the same as the @user instance variable throughout each action in the controller. The reason I have the except clause for the create action is because this action requires special authorization. When a responder is creating a reading for a requestor, that responder needs authorization to write to another user’s page. This is done by the unless || statement below in the #require_custom_authorization method. In this method, a user is considered authorized if the user_id in the url is the same as the current_user OR if the responder_id that is passed as a hidden input field in the form is found in the database and matches current_user.

Image for post
Image for post
An unless statement is utilized along with an “or” condition to account for the scenario where a custom reading is being conducted.

Finished Product

The Github repository for this application can be found at the link below. Feel free to clone the repo and run the app in your browser to play around with it. Even though the app is not live on the web, you can still conduct readings and track them locally. Any comments or questions are greatly appreciated!
https://github.com/dougschallmoser/connectarot-rails-app

Image for post
Image for post

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store