One place for hosting & domains

      Resources

      INAP Executive Spotlight: Jackie Coats, Senior Vice President, Human Resources


      In the INAP Executive Spotlight series, we interview senior leaders across the organization, hearing candid reflections about their careers, what they love about their work and big lessons learned along the way.

      Next in the series is Jackie Coats, Senior Vice President, Human Resources. In this role, she puts her passion for helping employees and leaders unlock their potential and accomplish goals to good use.

      In our conversation, Coats discussed what drew her to this role at INAP, how she’s working with the other senior leaders to build a strong company culture and much more. Jackie brings her enthusiasm to the forefront of everything she does. Read on to learn more.

      The interview has been lightly edited for clarity and length.

      You joined INAP in May as the Senior Vice President of Human Resources. What excites you most about this new role?

      The people at INAP are what attracted me to this role. I’d been consulting on my own and wasn’t in the market for going back to a regular full-time gig. I had the opportunity to come on as a contractor for INAP earlier this year. Every single person that I interacted with was smart, helpful and aligned with taking the business forward. The opportunity to be part of this team was a key driver in accepting the role. And as the company has now moved from public to private, I have the chance to build people functions that support the organization.

      You came into this role during the COVID-19 pandemic. How does this impact company culture and what’s being done to connect with employees during this time?

      The good thing is that our President and CEO Mike Sicoli genuinely cares about every single employee. It’s refreshing that he doesn’t delegate that to me alone as head of HR. All the senior leaders give a lot of thought to not only the productivity aspect of these times, as it’s important to keep a business running, but the emotional and personal impact that employees have undergone as a result of being remote. We’ve increased support tools and we’ve done surveys to check in with individual employees to take the pulse of the organization. We’ve connected leaders and given them tips on how to stay in sync with their teams. We’ve encouraged video one-on-ones in team meetings and all hands, etc. It’s something we definitely won’t stop beyond the pandemic. Knowing how our employees are feeling is important.

      With all the social unrest going on in the world, diversity and inclusion is really important. Can you tell us about the steps INAP is taking in those areas?

      We finalized the selection of a diversity, equity and inclusion consultant partner, and they have an amazing approach and lots of tools and partnerships that will help guide us. We’ll be doing work as a senior team, both together and individually, which I think is vital. We’ll also be doing an assessment of the organization to really get a baseline of where we stand. This consultant partner will help us identify areas where we need to focus.

      It’s obvious from looking at the organization that we need to support the growth and professional development of our women and people of color, because as you go up in the organization, there’s fewer and fewer people in those categories. We’ll be working on development activities and support for those individuals. We’ll take a hard look at our policies and practices to consider how we promote, hire and transfer.

      What changes have you see related to diversity and inclusion over your career? What do you still want to see?

      What I have learned over the years is that grassroots-type exercises really are more valuable than big, government-mandated exercises. I’ve seen a lot of success with mentoring programs where you identify individuals and what they’re trying to achieve from a development perspective, and you match them with a senior person who has that expertise. Both parties learn a tremendous amount.

      The need to hire quickly is generally what drives the hesitancy to take the time to find a diverse palate of candidates. As an organization and as a society, it’s absolutely critical that we develop our minority applicants and employees and go the extra mile to find people that bring diversity to the organization, because it’s critical for our success. There is a lot of data that shows businesses that are diverse are more productive and more successful.

      You’ve worked in HR for other tech companies prior to joining INAP. What do you like best about being in the industry?

      I’m a big believer that when you have pride in your organization, and in the products and services offered, employees are loyal and engaged. For me, technology touches absolutely everything. The fact that we’re powering and supporting businesses that are making our economy go brings a great sense of pride. And learning that some of our customers are in the gaming industry, I can connect that to having a kid who does all that stuff, so I love that.

      How you go about setting goals for your team?

      You need to have an overall vision for where you want your department or function to go. I talk a lot to my team about what we’re trying to achieve and what success would look like. We’re looking to add value to the organization, not just from an administrative or transactional standpoint. Our goal is to become consultative to the business leaders and help leaders and managers make excellent people decisions, support the growth of their individuals, improve the productivity of their teams, break down communication barriers across departments, recognize high performers and key contributors. That’s the big picture in what we’re trying to do.

      Did you take any detours to get to where you are today?

      I have a fashion merchandising degree and started in retail as a manager right out of the gate after graduating from college. Right away, I gravitated towards leadership and management. I realized that I had good transferrable skills, like hiring, coaching and training. I ended up taking a personnel training coordinator job at Lowe’s Home Centers, which tied the retail in with the HR function, and immediately saw a huge path of opportunity for me.

      Of all the qualities you possess, which ones have the greatest influence on your success?

      Enthusiasm. I bring a lot of positivity and enthusiasm for things that I believe in. My function should enable success, not get in the way. I have a quick ability to identify things that are getting in the way for people, and if they’re open to hearing it, I’m pretty good at helping them adjust their style to help them grow.

      What are some of the biggest lessons you’ve learned in your career?

      It’s important to surround yourself with people who possess talent and skills that you don’t have. I’ve learned to appreciate that you don’t have to have it all. You have to know what you need and you have to be able to find people to build a team with complementary skills. Bringing those complementary skills out in each of them has really helped me find success, for me and my teams.

      Is there anything you would do differently now if you were just starting out?

      I would’ve spent more time learning about data and metrics, and how to utilize them. Most business rely on data to help inform decisions and the people function is no different. Productivity, employee satisfaction and demographics are all KPIs that leaders need to know. Knowing the KPIs for your business helps to eliminate subjective decision making.

      Laura Vietmeyer


      READ MORE



      Source link

      19 Great Resources for Diverse Stock Photos


      The imagery you choose to share — on your website, social media accounts, and marketing materials — says a lot about your business.

      After all, a picture is worth a thousand words.

      Returning and potential customers, as well as employees and anyone else who crosses paths with your business, will look at the choices you make in your images. Are they reflected in those photographs? Do your visuals showcase true diversity and representation?

      “Inclusive imagery matters because our world is a beautiful and diverse place, and we need to embrace and celebrate that in terms of the visual content we put out into the world,” says Claudia Marks, Senior Art Director, iStock by Getty Images.

      “For brands, it’s an important consideration to make and, ideally, one that you make consistently with every visual choice,” Marks adds. “It’s safe to assume that most small businesses want to expand their reach, which means attracting as many customers as possible. It also means intentionally choosing imagery which is inclusive and, therefore, speaks to people broadly and welcomes them to interact with you and your business.”

      In this article, we’ll make the business case for diversity, share some tips for adding inclusive imagery to your site, and explain the growing demand for culturally diverse stock photos. Most importantly, we’ll share 19 great stock photo agencies and websites you can turn to when you want diverse, inclusive stock imagery for your business — no tired stereotypes here!

      We’ve got a lot to cover. Let’s dive in!

      Create a Website for All

      We make sure your website is fast, secure, and always up so you can focus on the things that really matter.

      The Business Case for Diversity

      There are plenty of reasons small business owners should opt for inclusive stock photos. Most importantly, it’s simply the right thing to do.

      But from a business perspective, it can also help a website owners’ bottom line. “The more you demonstrate that you welcome everyone or that your product is for everyone, the more people will be open to seeing what you have on offer and potentially becoming a customer of yours,” Marks says. “That’s a win-win for any business owner.”

      However, using inclusive stock art isn’t as easy as finding one person of color in an image and patting yourself on the back. There are certain guidelines to keep in mind to ensure you’re portraying true diversity.

      “Think about the concepts behind your business and what you are selling,” Marks says. “Make intentional choices in your imagery to ensure you show the kinds of customers you want to appeal to — all of them. Ask yourself if you unconsciously chose images that reflect your personal bias and, if so, challenge that. Know your audience . . . learn what they respond to and what resonates with them best.”

      How to Get Started With Diverse Imagery

      Remember to include everyone in your images. Marks suggests asking yourself a few key questions:

      • What is the widest your customer base can be?
      • How can you appeal to your core demographics, while still conveying the message behind your product or service?
      • What can you show your potential customers — as opposed to just telling them — so that it resonates more clearly and in a more meaningful way?

      To ensure that site owners give the appropriate credit when using images, familiarize yourself with Creative Commons and fair use rules. Take some time to read up on copyright restrictions; the best and simplest explanation can be found at creativecommonsusa.org.

      To quickly boil it down, examples of fair use in United States copyright law include using images for commentary, search engines, criticism, parody, news reporting, research, and nonprofit educational purposes. Before you post a photo, do your due diligence to make sure it’s okay to do so (especially if it could qualify as commercial use).

      The Increasing Demand for Diverse Photos

      In recent years, many new stock art agencies with diverse representation have cropped up to meet the demands of conscious business owners and media outlets. In addition, existing agencies, including Getty, have expanded to embrace more diversity.

      “Since launching LeanIn, we’ve expanded the ways we authentically — and inclusively — show the world and its beautiful humans,” Marks says. “We recently created the Nosotros Collection, which sought to expand our offering of Latinx content to more honestly depict Latinx people of all origins across the U.S. and North America and, ideally, banish false cultural stereotypes which pervade our media. We’ve also launched the Disability Collection in partnership with Verizon Media to more authentically show people of all abilities navigating everyday life, and the Disrupt Aging Collection in partnership with AARP to re-picture the 50+ community.”

      Plus, to support small businesses during the COVID-19 pandemic, Getty also made select content free to download.

      19 Great Resources for Diverse Stock Photos

      1. #WOCinTech Chat

      The WOCinTech Chat page on Flickr.

      The tech industry is notorious for being overwhelmingly male and white. #WoCinTech Chat is trying to change that stereotype by sharing photos of women of color in various technology fields. Even better, every single picture is free to use, thanks to the Creative Commons license. There’s just one caveat: Every photo has to be credited with either a link to the collection and/or the hashtag #WoCinTech Chat. When you think about it, it’s a double win, since it drives more visitors — and hopefully followers — to their site. The collection is curated by Flickr.

      2. UKBlackTech

      Group of Black co-workers having a meeting.
      Source: ukblacktech.com

      Most young people of color don’t see themselves represented in the fields of technology. When UKBlackTech — a British organization whose mission is to boost the growth of Black and ethnic minorities in the tech sector — learned about this, they organized a photoshoot to create the images that were missing. In addition to including people of color, they also aimed to include a distinctly British aesthetic. Under Creative Commons licensing, the collection can be used for free as long as UKBlackTech or www.ukblacktech.com is credited.

      3. Nappy

      Young man recording himself on a video camera.
      Source: nappy.co

      Diverse stock art shouldn’t just capture people in staged activities. Nappy offers “beautiful, high-res photos of Black and Brown people” in everyday life, ranging from exercising to eating, working, hanging out — you name it. And because Nappy wants to increase representation in the media, the images are free to use. They recommend giving them credit, but it isn’t mandatory. Nappy was created by Shade, a talent agency that specializes in diversity.

      4. CreateHer Stock

      The createherstock.com home page.

      CreateHER Stock isn’t a one-way business. Founder Neosha Gardner is creating a community by encouraging people to connect with her team on collaborations, including adding their own stock photos to the collection, and sending out a monthly email newsletter to keep everyone apprised of updates and giveaways. The stock photo site offers more than 3,500 photos of women of color spanning an array of categories, from workplace to lifestyle. Gardner launched the site when she couldn’t find photos of women of color for a blog post in 2014. They offer both royalty-free and paid options.

      5. TONL

      The tonl.co home page.

      On their website, TONL says, “A diverse mix of voices leads to better discussions for everyone.” The agency is living up to those words by focusing on images that show a glimpse into the lives of all types of people. They bring deeper context to their images by sharing text with each to provide a wider story. To make finding just the right images easier, the site’s offerings are organized into narratives such as taste, travel, tradition, technology, and trend. Within those categories, you’ll find an array of everything from religious images to family photos. They can be purchased à la carte or with a subscription.

      6. Picnoi

      The picnoi.com home page.

      When you can’t find stock image essentials that show a range of skin tones and races, there’s Picnoi to fill the gap. The co-op knows that most free stock images have very few options when it comes to showing people of color, so they created a space for bloggers, website owners, designers, publishers, advertisers, and anyone else to have free access to diverse images right at their fingertips. Picnoi doesn’t require attribution, but they appreciate it, so do them a solid and link to Picnoi to spread the word.

      7. The Gender Spectrum Collection: Stock Photos Beyond the Binary

      The genderphotos.vice.com home page.

      When talking about inclusive imagery, gender identity is often left out of the conversation. Luckily, The Gender Spectrum Collection fills that void with photos of transgender and non-binary folks. Powered by Vice media, the images are free to use. Organized by category — including lifestyle, relationships, and work, to name a few — Vice encourages clients to use the images mindfully to help bring awareness to gender bias and stereotypes, elevating the trans community along the way. The photos run the gamut of the LGBTQ spectrum, featuring people in all facets of life.

      8. DragonImages

      Example of a stock image from dragonimages.asia

      To ensure Asian people are represented correctly in imagery, Pressfoto Group, a stock photography house, launched DragonImages under their umbrella in 2012. Based in Asia, they ensure their photos accurately represent culture, customs, and ethnicities from across the continent. They shoot on location using Asian models, encompassing a wide array of categories and themes. In addition to being available at Pressfoto, many of their images can be found at popular stock photo agencies such as iStock, Shutterstock, and Fotolia. DragonImages purposely prices their photos very low —  often for less than a dollar — to make them widely accessible. More than 50,0000 of their photographs have been used all over the world. 

      9. Mocha Stock

      The mochastock.com home page.

      Sequoia Houston was constantly on the lookout for professional, diverse visuals she could use for campaigns at her marketing job, but they were next to impossible to find. She took matters into her own hands and launched Mocha Stock. From diverse stock images to illustrations to videos, Mocha Stock offers it all, showcasing people of color with a real vibe. A few of their themed galleries include celebrating women, business, and family. The royalty-free images are priced affordably to suit all budgets.

      10. Diversity Photos

      The diversityphotos.com/ home page.

      “Relevant. Authentic. Inclusive.” That’s how Diversity Photos describes their collection, and it’s spot on. They cover every topic you can think of and make it look believable, from business to health, spirituality, family, disabilities, and culture — all neatly organized into categories. With super high-quality and professional photos, they offer subscriptions or à la carte purchases at attainable prices.

      11. The Lean In Collection from LeanIn.org/Getty

      The Lean In collection home page.

      A team effort between Getty Images and LeanIn.org, the women’s empowerment nonprofit launched by Sheryl Sandberg, this photo library features more than 6,000 images of female leadership, both in work and life. Aiming to dispel gender stereotypes and imagery that depicts patriarchy, The “Lean In Collection” shows women and girls as equals and empowered. “The goal is to shift perceptions, overturn clichés, and incorporate authentic images of women and men into media and advertising,” Marks says.

      12. The 67 Percent Collection from Refinery29/Getty

      Example stock image from The 67 Percent Collection.

      This is a collection of imagery created by the team at Refinery29 to dive deeper into how millennial and Gen Z women view themselves and the world — unapologetically themselves and embracing every aspect of who they are,” Marks says. It’s all about raw images of women from various walks of life and backgrounds.

      13. MuslimGirl.com Collection from Getty

      Example stock image from the MuslimGirl.com collection

      “We partnered with their founder, Amani al-Khatahtbeh, to purposefully change how young, modern Muslim women and girls are depicted in the media and advertising,” Marks says. “Whether they choose to wear a hijab or not, they are more than they have been depicted in pop culture.  They have the same aspirations and emotions and passions and intelligence as all modern girls and women and should be depicted as such to normalize their existence in our world and specifically the West.”

      14. Shestock from Blend Images

      Images of women by women doesn’t sound revolutionary, but it was when Shestock was launched in 2012, making it the very first woman-centric stock image collection. In addition to supporting female photographers, it aims to eliminate gender bias and show women in more authentic and empowering situations. For example, Shestock shares photos of women in STEM fields to encourage young girls. The collection is available for purchase through Blend Images.

      15. LGBT Photos by Pexels

      The LGBTQ spectrum truly is as broad as a rainbow, and Pexels captures this sentiment in their curated section of LGBTQ photos. From portraits to lifestyle shots and everything in between, Pexels covers the bases with an ethnically diverse group of people in an authentic way. Even better, all of the photos and videos are free. Attribution isn’t necessary, but it is appreciated by both Pexels and the photographers.

      DreamHost Takes Inclusivity Seriously

      We regularly report on diversity, accessibility, and representation in the tech industry. Subscribe to our monthly newsletter so you never miss an article.

      16. TetraImages.com

      The latest collection from Tetra is Blend images, which is all about photography and footage of multicultural and diverse people shot by artists from across the globe. They cover any category you can think of — small business to city life, beauty, nature, food, holidays, seasons, health living, education, Americana, and pharmaceuticals, to name a few. The conceptual images are fresh, modern, and realistic, and all are available for editorial and commercial licensing.

      17. The LGBT section at Twenty20

      Example stock image from the Twenty20.com collection

      Twenty20 fills their LGBTQ section with people of color, a range of identities, and striking images that deliver a deeper message. To make it easier to find exactly what you’re looking for, their LGBTQ section is organized into several categories, such as Pride, couples, and happy people. They offer subscriptions from $16.50 per month.

      18. PhotoAbility

      The photoability.net home page.

      It doesn’t get more authentic than PhotoAbility and their models. Every single person portrayed in the images has a disability and a portion of each sale goes directly to them. The photos feature adults and children with disabilities in various settings, including travel, sports, business, and lifestyle, aiming to increase positive imagery of people who use wheelchairs, canes, walkers, guide dogs, and other mobility devices. They offer a range of prices to fit every budget, with a deep discount for advocacy groups.

      19. Canva’s Natural Woman Collection

      Tired of the male gaze? Canva is too, which is where their Natural Woman Collection comes in. Authentic and true to life, it captures women in their natural state, whether that’s in nature, striking a yoga pose, taking selfies with friends, or with their families. Canva offers both free and premium shots to make the most of your budget.



      Source link

      How To Create Nested Resources for a Ruby on Rails Application


      Introduction

      Ruby on Rails is a web application framework written in Ruby that offers developers an opinionated approach to application development. Working with Rails gives developers:

      • Conventions for handling things like routing, stateful data, and asset management.
      • A firm grounding in the model-view-controller (MCV) architectural pattern, which separates an application’s logic, located in models, from the presentation and routing of application information.

      As you add complexity to your Rails applications, you will likely work with multiple models, which represent your application’s business logic and interface with your database. Adding related models means establishing meaningful relationships between them, which then affect how information gets relayed through your application’s controllers, and how it is captured and presented back to users through views.

      In this tutorial, you will build on an existing Rails application that offers users facts about sharks. This application already has a model for handling shark data, but you will add a nested resource for posts about individual sharks. This will allow users to build out a wider body of thoughts and opinions about individual sharks.

      Prerequisites

      To follow this tutorial, you will need:

      • A local machine or development server running Ubuntu 18.04. Your development machine should have a non-root user with administrative privileges and a firewall configured with ufw. For instructions on how to set this up, see our Initial Server Setup with Ubuntu 18.04 tutorial.
      • Node.js and npm installed on your local machine or development server. This tutorial uses Node.js version 10.16.3 and npm version 6.9.0. For guidance on installing Node.js and npm on Ubuntu 18.04, follow the instructions in the “Installing Using a PPA” section of How To Install Node.js on Ubuntu 18.04.
      • Ruby, rbenv, and Rails installed on your local machine or development server, following Steps 1-4 in How To Install Ruby on Rails with rbenv on Ubuntu 18.04. This tutorial uses Ruby 2.5.1, rbenv 1.1.2, and Rails 5.2.3.
      • SQLite installed, and a basic shark information application created, following the directions in How To Build a Ruby on Rails Application.

      Step 1 — Scaffolding the Nested Model

      Our application will take advantage of Active Record associations to build out a relationship between Shark and Post models: posts will belong to particular sharks, and each shark can have multiple posts. Our Shark and Post models will therefore be related through belongs_to and has_many associations.

      The first step to building out the application in this way will be to create a Post model and related resources. To do this, we can use the rails generate scaffold command, which will give us a model, a database migration to alter the database schema, a controller, a full set of views to manage standard Create, Read, Update, and Delete (CRUD) operations, and templates for partials, helpers, and tests. We will need to modify these resources, but using the scaffold command will save us some time and energy since it generates a structure we can use as a starting point.

      First, make sure that you are in the sharkapp directory for the Rails project that you created in the prerequisites:

      Create your Post resources with the following command:

      • rails generate scaffold Post body:text shark:references

      With body:text, we’re telling Rails to include a body field in the posts database table — the table that maps to the Post model. We’re also including the :references keyword, which sets up an association between the Shark and Post models. Specifically, this will ensure that a foreign key representing each shark entry in the sharks database is added to the posts database.

      Once you have run the command, you will see output confirming the resources that Rails has generated for the application. Before moving on, you can check your database migration file to look at the relationship that now exists between your models and database tables. Use the following command to look at the contents of the file, making sure to substitute the timestamp on your own migration file for what’s shown here:

      • cat db/migrate/20190805132506_create_posts.rb

      You will see the following output:

      Output

      class CreatePosts < ActiveRecord::Migration[5.2] def change create_table :posts do |t| t.text :body t.references :shark, foreign_key: true t.timestamps end end end

      As you can see, the table includes a column for a shark foreign key. This key will take the form of model_name_id — in our case, shark_id.

      Rails has established the relationship between the models elsewhere as well. Take a look at the newly generated Post model with the following command:

      Output

      class Post < ApplicationRecord belongs_to :shark end

      The belongs_to association sets up a relationship between models in which a single instance of the declaring model belongs to a single instance of the named model. In the case of our application, this means that a single post belongs to a single shark.

      In addition to setting this relationship, the rails generate scaffold command also created routes and views for posts, as it did for our shark resources in Step 3 of How To Build a Ruby on Rails Application.

      This is a useful start, but we will need to configure some additional routing and solidify the Active Record association for the Shark model in order for the relationship between our models and routes to work as desired.

      Step 2 — Specifying Nested Routes and Associations for the Parent Model

      Rails has already set the belongs_to association in our Post model, thanks to the :references keyword in the rails generate scaffold command, but in order for that relationship to function properly we will need to specify a has_many association in our Shark model as well. We will also need to make changes to the default routing that Rails gave us in order to make post resources the children of shark resources.

      To add the has_many association to the Shark model, open app/models/shark.rb using nano or your favorite editor:

      Add the following line to the file to establish the relationship between sharks and posts:

      ~/sharkapp/app/models/shark.rb

      class Shark < ApplicationRecord
        has_many :posts
        validates :name, presence: true, uniqueness: true
        validates :facts, presence: true
      end
      

      One thing that is worth thinking about here is what happens to posts once a particular shark is deleted. We likely do not want the posts associated with a deleted shark persisting in the database. To ensure that any posts associated with a given shark are eliminated when that shark is deleted, we can include the dependent option with the association.

      Add the following code to the file to ensure that the destroy action on a given shark deletes any associated posts:

      ~/sharkapp/app/models/post.rb

      class Shark < ApplicationRecord
        has_many :posts , dependent: :destroy
        validates :name, presence: true, uniqueness: true
        validates :facts, presence: true
      end
      

      Once you have finished making these changes, save and close the file. If you are using nano, you can do this by pressing CTRL+X, Y, then ENTER.

      Next, open your config/routes.rb file to modify the relationship between your resourceful routes:

      Currently, the file looks like this:

      ~/sharkapp/config/routes.rb

      Rails.application.routes.draw do
        resources :posts 
        resources :sharks
      
        root 'sharks#index'
        # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
      end
      

      The current code establishes an independent relationship between our routes, when what we would like to express is a dependent relationship between sharks and their associated posts.

      Let’s update our route declaration to make :sharks the parent of :posts. Update the code in the file to look like the following:

      ~/sharkapp/config/routes.rb

      Rails.application.routes.draw do
        resources :sharks do
          resources :posts
        end
        root 'sharks#index'
        # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
      end
      

      Save and close the file when you are finished editing.

      With these changes in place, you can move on to updating your posts controller.

      Step 3 — Updating the Posts Controller

      The association between our models gives us methods that we can use to create new post instances associated with particular sharks. To use these methods, we will need to add them our posts controller.

      Open the posts controller file:

      • nano app/controllers/posts_controller.rb

      Currently, the file looks like this:

      ~/sharkapp/controllers/posts_controller.rb

      class PostsController < ApplicationController
        before_action :set_post, only: [:show, :edit, :update, :destroy]
      
        # GET /posts
        # GET /posts.json
        def index
          @posts = Post.all
        end
      
        # GET /posts/1
        # GET /posts/1.json
        def show
        end
      
        # GET /posts/new
        def new
          @post = Post.new
        end
      
        # GET /posts/1/edit
        def edit
        end
      
        # POST /posts
        # POST /posts.json
        def create
          @post = Post.new(post_params)
      
          respond_to do |format|
            if @post.save
              format.html { redirect_to @post, notice: 'Post was successfully created.' }
              format.json { render :show, status: :created, location: @post }
            else
              format.html { render :new }
              format.json { render json: @post.errors, status: :unprocessable_entity }
            end
          end
        end
      
        # PATCH/PUT /posts/1
        # PATCH/PUT /posts/1.json
        def update
          respond_to do |format|
            if @post.update(post_params)
              format.html { redirect_to @post, notice: 'Post was successfully updated.' }
              format.json { render :show, status: :ok, location: @post }
            else
              format.html { render :edit }
              format.json { render json: @post.errors, status: :unprocessable_entity }
            end
          end
        end
      
        # DELETE /posts/1
        # DELETE /posts/1.json
        def destroy
          @post.destroy
          respond_to do |format|
            format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
            format.json { head :no_content }
          end
        end
      
        private
          # Use callbacks to share common setup or constraints between actions.
          def set_post
            @post = Post.find(params[:id])
          end
      
          # Never trust parameters from the scary internet, only allow the white list through.
          def post_params
            params.require(:post).permit(:body, :shark_id)
          end
      end
      

      Like our sharks controller, this controller’s methods work with instances of the associated Post class. For example, the new method creates a new instance of the Post class, the index method grabs all instances of the class, and the set_post method uses find and params to select a particular post by id. If, however, we want our post instances to be associated with particular shark instances, then we will need to modify this code, since the Post class is currently operating as an independent entity.

      Our modifications will make use of two things:

      • The methods that became available to us when we added the belongs_to and has_many associations to our models. Specifically, we now have access to the build method thanks to the has_many association we defined in our Shark model. This method will allow us to create a collection of post objects associated with a particular shark object, using the shark_id foreign key that exists in our posts database.
      • The routes and routing helpers that became available when we created a nested posts route. For a full list of example routes that become available when you create nested relationships between resources, see the Rails documentation. For now, it will be enough for us to know that for each specific shark — say sharks/1 — there will be an associated route for posts related to that shark: sharks/1/posts. There will also be routing helpers like shark_posts_path(@shark) and edit_sharks_posts_path(@shark) that refer to these nested routes.

      In the file, we’ll begin by writing a method, get_shark, that will run before each action in the controller. This method will create a local @shark instance variable by finding a shark instance by shark_id. With this variable available to us in the file, it will be possible to relate posts to a specific shark in the other methods.

      Above the other private methods at the bottom of the file, add the following method:

      ~/sharkapp/controllers/posts_controller.rb

      . . . 
      private
        def get_shark
          @shark = Shark.find(params[:shark_id])
        end
        # Use callbacks to share common setup or constraints between actions.
      . . . 
      

      Next, add the corresponding filter to the top of the file, before the existing filter:

      ~/sharkapp/controllers/posts_controller.rb

      class PostsController < ApplicationController
        before_action :get_shark
      

      This will ensure that get_shark runs before each action defined in the file.

      Next, you can use this @shark instance to rewrite the index method. Instead of grabbing all instances of the Post class, we want this method to return all post instances associated with a particular shark instance.

      Modify the index method to look like this:

      ~/sharkapp/controllers/posts_controller.rb

      . . .
        def index
          @posts = @shark.posts
        end
      . . .
      

      The new method will need a similar revision, since we want a new post instance to be associated with a particular shark. To achieve this, we can make use of the build method, along with our local @shark instance variable.

      Change the new method to look like this:

      ~/sharkapp/controllers/posts_controller.rb

      . . . 
        def new
          @post = @shark.posts.build
        end
      . . . 
      

      This method creates a post object that’s associated with the specific shark instance from the get_shark method.

      Next, we’ll address the method that’s most closely tied to new: create. The create method does two things: it builds a new post instance using the parameters that users have entered into the new form, and, if there are no errors, it saves that instance and uses a route helper to redirect users to where they can see the new post. In the case of errors, it renders the new template again.

      Update the create method to look like this:

      ~/sharkapp/controllers/posts_controller.rb

        def create
          @post = @shark.posts.build(post_params)
      
              respond_to do |format|
               if @post.save  
                  format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' }
                  format.json { render :show, status: :created, location: @post }
               else
                  format.html { render :new }
                  format.json { render json: @post.errors, status: :unprocessable_entity }
            end
          end
        end
      

      Next, take a look at the update method. This method uses a @post instance variable, which is not explicitly set in the method itself. Where does this variable come from?

      Take a look at the filters at the top of the file. The second, auto-generated before_action filter provides an answer:

      ~/sharkapp/controllers/posts_controller.rb

      class PostsController < ApplicationController
        before_action :get_shark
        before_action :set_post, only: [:show, :edit, :update, :destroy]
        . . .
      

      The update method (like show, edit, and destroy) takes a @post variable from the set_post method. That method, listed under the get_shark method with our other private methods, currently looks like this:

      ~/sharkapp/controllers/posts_controller.rb

      . . . 
      private
      . . . 
        def set_post
          @post = Post.find(params[:id])
        end
      . . .
      

      In keeping with the methods we’ve used elsewhere in the file, we will need to modify this method so that @post refers to a particular instance in the collection of posts that’s associated with a particular shark. Keep the build method in mind here — thanks to the associations between our models, and the methods (like build) that are available to us by virtue of those associations, each of our post instances is part of a collection of objects that’s associated with a particular shark. So it makes sense that when querying for a particular post, we would query the collection of posts associated with a particular shark.

      Update set_post to look like this:

      ~/sharkapp/controllers/posts_controller.rb

      . . . 
      private
      . . . 
        def set_post
          @post = @shark.posts.find(params[:id])
        end
      . . .
      

      Instead of finding a particular instance of the entire Post class by id, we instead search for a matching id in the collection of posts associated with a particular shark.

      With that method updated, we can look at the update and destroy methods.

      The update method makes use of the @post instance variable from set_post, and uses it with the post_params that the user has entered in the edit form. In the case of success, we want Rails to send the user back to the index view of the posts associated with a particular shark. In the case of errors, Rails will render the edit template again.

      In this case, the only change we will need to make is to the redirect_to statement, to handle successful updates. Update it to redirect to shark_post_path(@shark), which will redirect to the index view of the selected shark’s posts:

      ~/sharkapp/controllers/posts_controller.rb

      . . . 
        def update
          respond_to do |format|
            if @post.update(post_params)
              format.html { redirect_to shark_post_path(@shark), notice: 'Post was successfully updated.' }
              format.json { render :show, status: :ok, location: @post }
            else
              format.html { render :edit }
              format.json { render json: @post.errors, status: :unprocessable_entity }
            end
          end
        end
      . . .
      

      Next, we will make a similar change to the destroy method. Update the redirect_to method to redirect requests to shark_posts_path(@shark) in the case of success:

      ~/sharkapp/controllers/posts_controller.rb

      . . . 
        def destroy
          @post.destroy
           respond_to do |format|
            format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' }
            format.json { head :no_content }
          end
        end
      . . .
      

      This is the last change we will make. You now have a posts controller file that looks like this:

      ~/sharkapp/controllers/posts_controller.rb

      class PostsController < ApplicationController
        before_action :get_shark
        before_action :set_post, only: [:show, :edit, :update, :destroy]
      
        # GET /posts
        # GET /posts.json
        def index
          @posts = @shark.posts
        end
      
        # GET /posts/1
        # GET /posts/1.json
        def show
        end
      
        # GET /posts/new
        def new
          @post = @shark.posts.build
        end
      
        # GET /posts/1/edit
        def edit
        end
      
        # POST /posts
        # POST /posts.json
        def create
          @post = @shark.posts.build(post_params)
      
              respond_to do |format|
               if @post.save  
                  format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' }
                  format.json { render :show, status: :created, location: @post }
               else
                  format.html { render :new }
                  format.json { render json: @post.errors, status: :unprocessable_entity }
            end
          end
        end
      
        # PATCH/PUT /posts/1
        # PATCH/PUT /posts/1.json
        def update
          respond_to do |format|
            if @post.update(post_params)
              format.html { redirect_to shark_post_path(@shark), notice: 'Post was successfully updated.' }
              format.json { render :show, status: :ok, location: @post }
            else
              format.html { render :edit }
              format.json { render json: @post.errors, status: :unprocessable_entity }
            end
          end
        end
      
        # DELETE /posts/1
        # DELETE /posts/1.json
        def destroy
          @post.destroy
          respond_to do |format|
            format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' }
            format.json { head :no_content }
          end
        end
      
        private
      
         def get_shark
           @shark = Shark.find(params[:shark_id])
         end
          # Use callbacks to share common setup or constraints between actions.
          def set_post
            @post = @shark.posts.find(params[:id])
          end
      
          # Never trust parameters from the scary internet, only allow the white list through.
          def post_params
            params.require(:post).permit(:body, :shark_id)
          end
      end
      

      The controller manages how information is passed from the view templates to the database and vice versa. Our controller now reflects the relationship between our Shark and Post models, in which posts are associated with particular sharks. We can move on to modifying the view templates themselves, which are where users will pass in and modify post information about particular sharks.

      Step 4 — Modifying Views

      Our view template revisions will involve changing the templates that relate to posts, and also modifying our sharks show view, since we want users to see the posts associated with particular sharks.

      Let’s start with the foundational template for our posts: the form partial that is reused across multiple post templates. Open that form now:

      • nano app/views/posts/_form.html.erb

      Rather than passing only the post model to the form_with form helper, we will pass both the shark and post models, with post set as a child resource.

      Change the first line of the file to look like this, reflecting the relationship between our shark and post resources:

      ~/sharkapp/views/posts/_form.html.erb

      <%= form_with(model: [@shark, post], local: true) do |form| %>
      . . . 
      

      Next, delete the section that lists the shark_id of the related shark, since this is not essential information in the view.

      The finished form, complete with our edits to the first line and without the deleted shark_id section, will look like this:

      ~/sharkapp/views/posts/_form.html.erb

      <%= form_with(model: [@shark, post], local: true) do |form| %>
        <% if post.errors.any? %>
          <div id="error_explanation">
            <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>
      
            <ul>
            <% post.errors.full_messages.each do |message| %>
              <li><%= message %></li>
            <% end %>
            </ul>
          </div>
        <% end %>
      
        <div class="field">
          <%= form.label :body %>
          <%= form.text_area :body %>
        </div>
      
        <div class="actions">
          <%= form.submit %>
        </div>
      <% end %>
      

      Save and close the file when you are finished editing.

      Next, open the index view, which will show the posts associated with a particular shark:

      • nano app/views/posts/index.html.erb

      Thanks to the rails generate scaffold command, Rails has generated the better part of the template, complete with a table that shows the body field of each post and its associated shark.

      Much like the other code we have already modified, however, this template treats posts as independent entities, when we would like to make use of the associations between our models and the collections and helper methods that these associations give us.

      In the body of the table, make the following updates:

      First, update post.shark to post.shark.name, so that the table will include the name field of the associated shark, rather than identifying information about the shark object itself:

      ~/sharkapp/app/views/posts/index.html.erb

      . . . 
        <tbody>
          <% @posts.each do |post| %>
            <tr>
              <td><%= post.body %></td>
              <td><%= post.shark.name %></td>
      . . . 
      

      Next, change the Show redirect to direct users to the show view for the associated shark, since they will most likely want a way to navigate back to the original shark. We can make use of the @shark instance variable that we set in the controller here, since Rails makes instance variables created in the controller available to all views. We’ll also change the text for the link from Show to Show Shark, so that users will better understand its function.

      Update the this line to the following:

      ~/sharkapp/app/views/posts/index.html.erb

      . . . 
        <tbody>
          <% @posts.each do |post| %>
            <tr>
              <td><%= post.body %></td>
              <td><%= post.shark.name %></td>
              <td><%= link_to 'Show Shark', [@shark] %></td>
      

      In the next line, we want to ensure that users are routed the right nested path when they go to edit a post. This means that rather than being directed to posts/post_id/edit, users will be directed to sharks/shark_id/posts/post_id/edit. To do this, we’ll use the shark_post_path routing helper and our models, which Rails will treat as URLs. We’ll also update the link text to make its function clearer.

      Update the Edit line to look like the following:

      ~/sharkapp/app/views/posts/index.html.erb

      . . . 
        <tbody>
          <% @posts.each do |post| %>
            <tr>
              <td><%= post.body %></td>
              <td><%= post.shark.name %></td>
              <td><%= link_to 'Show Shark', [@shark] %></td>
              <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
      

      Next, let’s add a similar change to the Destroy link, updating its function in the string, and adding our shark and post resources:

      ~/sharkapp/app/views/posts/index.html.erb

      . . . 
        <tbody>
          <% @posts.each do |post| %>
            <tr>
              <td><%= post.body %></td>
              <td><%= post.shark.name %></td>
              <td><%= link_to 'Show Shark', [@shark] %></td>
              <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
              <td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td>
      

      Finally, at the bottom of the form, we will want to update the New Post path to take users to the appropriate nested path when they want to create a new post. Update the last line of the file to make use of the new_shark_post_path(@shark) routing helper:

      ~/sharkapp/app/views/posts/index.html.erb

      . . . 
      <%= link_to 'New Post', new_shark_post_path(@shark) %>
      

      The finished file will look like this:

      ~/sharkapp/app/views/posts/index.html.erb

      <p id="notice"><%= notice %></p>
      
      <h1>Posts</h1>
      
      <table>
        <thead>
          <tr>
            <th>Body</th>
            <th>Shark</th>
            <th colspan="3"></th>
          </tr>
        </thead>
      
        <tbody>
          <% @posts.each do |post| %>
            <tr>
              <td><%= post.body %></td>
              <td><%= post.shark.name %></td>
              <td><%= link_to 'Show Shark', [@shark] %></td>
              <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
              <td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td>
            </tr>
          <% end %>
        </tbody>
      </table>
      
      <br>
      
      <%= link_to 'New Post', new_shark_post_path(@shark) %>
      

      Save and close the file when you are finished editing.

      The other edits we will make to post views won’t be as numerous, since our other views use the form partial we have already edited. However, we will want to update the link_to references in the other post templates to reflect the changes we have made to our form partial.

      Open app/views/posts/new.html.erb:

      • nano app/views/posts/new.html.erb

      Update the link_to reference at the bottom of the file to make use of the shark_posts_path(@shark) helper:

      ~/sharkapp/app/views/posts/new.html.erb

      . . . 
      <%= link_to 'Back', shark_posts_path(@shark) %>
      

      Save and close the file when you are finished making this change.

      Next, open the edit template:

      • nano app/views/posts/edit.html.erb

      In addition to the Back path, we’ll update Show to reflect our nested resources. Change the last two lines of the file to look like this:

      ~/sharkapp/app/views/posts/edit.html.erb

      . . . 
      <%= link_to 'Show', [@shark, @post] %> |
      <%= link_to 'Back', shark_posts_path(@shark) %>
      

      Save and close the file.

      Next, open the show template:

      • nano app/views/posts/show.html.erb

      Make the following edits to the Edit and Back paths at the bottom of the file:

      ~/sharkapp/app/views/posts/edit.html.erb

      . . .
      <%= link_to 'Edit', edit_shark_post_path(@shark, @post) %> |
      <%= link_to 'Back', shark_posts_path(@shark) %>
      

      Save and close the file when you are finished.

      As a final step, we will want to update the show view for our sharks so that posts are visible for individual sharks. Open that file now:

      • nano app/views/sharks/show.html.erb

      Our edits here will include adding a Posts section to the form and an Add Post link at the bottom of the file.

      Below the Facts for a given shark, we will add a new section that iterates through each instance in the collection of posts associated with this shark, outputting the body of each post.

      Add the following code below the Facts section of the form, and above the redirects at the bottom of the file:

      ~/sharkapp/app/views/sharks/show.html.erb

      . . .
      <p>
        <strong>Facts:</strong>
        <%= @shark.facts %>
      </p>
      
      <h2>Posts</h2>
      <% for post in @shark.posts %>
          <ul>
            <li><%= post.body %></li>
        </ul>
      <% end %>
      
      <%= link_to 'Edit', edit_shark_path(@shark) %> |
      . . . 
      

      Next, add a new redirect to allow users to add a new post for this particular shark:

      ~/sharkapp/app/views/sharks/show.html.erb

      . . .
      <%= link_to 'Edit', edit_shark_path(@shark) %> |
      <%= link_to 'Add Post', shark_posts_path(@shark) %> |
      <%= link_to 'Back', sharks_path %>
      

      Save and close the file when you are finished editing.

      You have now made changes to your application’s models, controllers, and views to ensure that posts are always associated with a particular shark. As a final step, we can add some validations to our Post model to guarantee consistency in the data that’s saved to the database.

      Step 5 — Adding Validations and Testing the Application

      In Step 5 of How To Build a Ruby on Rails Application, you added validations to your Shark model to ensure uniformity and consistency in the data that gets saved to the sharks database. We’ll now take a similar step to ensure guarantees for the posts database as well.

      Open the file where your Post model is defined:

      Here, we want to ensure that posts are not blank and that they don’t duplicate content other users may have posted. To achieve this, add the following line to the file:

      ~/sharkapp/app/models/post.rb

      class Post < ApplicationRecord
        belongs_to :shark
        validates :body, presence: true, uniqueness: true
      end
      

      Save and close the file when you are finished editing.

      With this last change in place, you are ready to run your migrations and test the application.

      First, run your migrations:

      Next, start your server. If you’re working locally, you can do so by running:

      If you are working on a development server, run the following command instead:

      • rails s --binding=your_server_ip

      Navigate to your application’s root at http://localhost:3000 or http://your_server_ip:3000.

      The prerequisite Rails project tutorial walked you through adding and editing a Great White shark entry. If you have not added any further sharks, the application landing page will look like this:

      Shark App Landing Page

      Click on Show next to the Great White’s name. This will take you to the show view for this shark. You will see the name of the shark and its facts, and a Posts header with no content. Let’s add a post to populate this part of the form.

      Click on Add Post below the Posts header. This will bring you to the post index view, where you will have the chance to select New Post:

      Post Index View

      Thanks to the authentication mechanisms you put in place in Step 6 of How To Build a Ruby on Rails Application, you may be asked to authenticate with the username and password you created in that Step, depending on whether or not you have created a new session.

      Click on New Post, which will bring you to your post new template:

      New Post

      In the Body field, type, “These sharks are scary!”

      New Shark Post

      Click on Create Post. You will be redirected to the index view for all posts that belong to this shark:

      Post Success

      With our post resources working, we can now test our data validations to ensure that only desired data gets saved to the database.

      From the index view, click on New Post. In the Body field of the new form, try entering “These sharks are scary!” again:

      Repeat Shark Post

      Click on Create Post. You will see the following error:

      Unique Post Error

      Click on Back to return to the main posts page.

      To test our other validation, click on New Post again. Leave the post blank and click Create Post. You will see the following error:

      Blank Post Error

      With your nested resources and validations working properly, you now have a working Rails application that you can use as a starting point for further development.

      Conclusion

      With your Rails application in place, you can now work on things like styling and developing other front-end components. If you would like to learn more about routing and nested resources, the Rails documentation is a great place to start.

      To learn more about integrating front-end frameworks with your application, take a look at How To Set Up a Ruby on Rails Project with a React Frontend.



      Source link