Fitness App #499283427

I have always had a passion for health and fitness so when the time came to build my Ruby on Rails project for the Flatiron School I was amped. I had so many ideas for my app and with so many fitness apps on the market my app needed something special to stand out. However, bringing those ideas to reality is not so easy especially when there is a deadline to submit the project. So I just stuck to the minimum viable product and focused on the requirements. Even without the implementation of my ideas building this application was still challenging. Here I will be walking you through the main obstacle I came across when building this application and how I overcame them.

One of the requirements, and the most challenging, was to: “…include a many-to-many relationship implemented with has_many :through associations. The join table must include a user-submittable attribute — that is to say, some attribute other than its foreign keys that can be submitted by the app’s user.” Since my app’s main functionality was the creation of workouts and workouts consist of exercises, sets and reps I created a exercises_workouts to join my Workout and Exercise models and gave it sets and reps as extra attributes.

The issue began when I was creating the form for new workouts. I had no idea how to access the sets and reps attributes from my workout model. As I retraced previous lessons/labs I came across the fields_for form helper that the Action View gives to us. This helper is called upon the Form Builder instance that form_for or form_with yields to the block. The fields_for accepts an argument of an object associated to the main object, in my case exercises_workouts. Then yields another Form Builder object to its own block. Being inside this fields_for gives us access to the sets and reps attributes that we need to create a workout. And all this looks something like this:

One thing to always remember when dealing with nested attributes and strong params, is that every symbol in a form helper and every key in a strong params method must correspond to a writer method for the Form Builders object. For my workout model I needed a writer for exercises_workouts. You can either use the accepts_nested_attributes_for :associated_model macro or write it manually in your model. If I was to write this method manually in my model this is what it will look like

def exercises_workouts_attributes=(exercises_workouts_attributes)    exercises_workouts_attributes.each do |exercise_workout|    endend

Be sure to make it plural if your model has_many of the associated model or singular if it is a belongs_to relationship. Also, I must say that although you can pass this macro some options such as reject_if {code_that_returns boolean_value to prevent invalid empty attributes in the associated object, some Rubyists prefer to write this method manually as it is more flexible. Now this wont work quite yet. There a few more things we must do in the controller before this works.

The way fields_for works is by iterating over the parent object’s association collection. This means that it will make fields for however many objects there are in that collection. If there are no associated objects there will be no fields. So we must create some empty objects and associate them to the parent. This is done inside our ‘new’ action right before our form is rendered.

Lastly, we must modify our strong params method to accept nested attributes from the form. Don’t forget to append the nested attributes to the .permit argument. Placing an array before other keys will cause an error.

Personally, I feel projects are the best way to develop your programming skills. There is no better feeling than doing your own research on a topic and implementing your application. This won’t always be the case. There are times where you simply need to talk it out with someone. I am very fortunate to belong_to a great community of developers who are always willing to help and support each other. Shout out to the 10/19/20 ft-web cohort!

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