<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: jhalfman</title>
    <description>The latest articles on Forem by jhalfman (@jhalfman).</description>
    <link>https://forem.com/jhalfman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F844437%2Fe2dbcca3-6992-4577-9b5b-81b798181961.png</url>
      <title>Forem: jhalfman</title>
      <link>https://forem.com/jhalfman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jhalfman"/>
    <language>en</language>
    <item>
      <title>Action Mailer in Ruby on Rails (and how to deploy with Gmail)</title>
      <dc:creator>jhalfman</dc:creator>
      <pubDate>Fri, 24 Mar 2023 18:44:52 +0000</pubDate>
      <link>https://forem.com/jhalfman/action-mailer-in-ruby-on-rails-and-how-to-deploy-1nlm</link>
      <guid>https://forem.com/jhalfman/action-mailer-in-ruby-on-rails-and-how-to-deploy-1nlm</guid>
      <description>&lt;h1&gt;
  
  
  Active Mailer
&lt;/h1&gt;

&lt;p&gt;If you've ever wondered how to get your rails server to send out emails, Ruby on Rails has fortunately provided just the tool.  Action Mailer is a class that inherits from ActionMailer::Base, which inherits from AbstractController::Base. This means that Action Mailer functions a lot like an Action Controller, but they are kept in app/mailers instead of app/controllers.  Just like with a controller, we can send a mailer different params and craft what is sent by the mailer actions. Once we have the mailer set up, we can call it from inside our other controllers!&lt;/p&gt;

&lt;h1&gt;
  
  
  Set up
&lt;/h1&gt;

&lt;p&gt;Mailers can be generated just like other resources using &lt;code&gt;rails generate mailer &amp;lt;mailer name&amp;gt;&lt;/code&gt;, where &amp;lt;mailer name&amp;gt; is what you want to call your mailer. This will generate a file called application_mailer.rb (if it doesn't already exist), along with the mailer with the name you specified. The ApplicationMailer class is set to inherit from ActionMailer::Base, while your specified mailer inherits from ApplicationMailer.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwu1twergojkii923mwu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwu1twergojkii923mwu3.png" alt="Image description"&gt;&lt;/a&gt; In this example, we're creating a UserMailer to handle emails involved with user actions, like signing up for a web service.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4jeloi1dasq2djo8mcy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4jeloi1dasq2djo8mcy.png" alt="Image description"&gt;&lt;/a&gt;The default method is used to set the default values for each mailer, and here the default :from value is being set to specify which email address this mailer sends from. The ApplicationMailer default can be overridden within the individual mailers with their own default values, and the mailers' default values can be overridden per individual email.&lt;/p&gt;
&lt;h1&gt;
  
  
  Mailer methods
&lt;/h1&gt;

&lt;p&gt;As with a controller, we can define methods inside our mailers to help craft and send our emails. For example, we can create a method to be called when a user creates a new account. The mailer has access to the params hash, so we can send valuable information, such as an email address or username, to the mailer to be utilized in the email creation.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F377q3vaspodutwtl8ugx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F377q3vaspodutwtl8ugx.png" alt="Image description"&gt;&lt;/a&gt;The &lt;code&gt;mail&lt;/code&gt; action is what creates the email to be sent. Inside mail, we can declare the :to value as the recipient's email address, and the :subject value with our email subject. As seen above, we can utilize variables within our mail action to help specify these values.&lt;/p&gt;
&lt;h1&gt;
  
  
  Layouts and Views
&lt;/h1&gt;

&lt;p&gt;When we generated our mailer, we should also have created some files in our views folder.  /app/views/layouts/mailer.html.erb and /app/views/layouts/mailer.text.erb are utilized as the general email layout declared by &lt;code&gt;layout 'mailer'&lt;/code&gt; in our ApplicationMailer.  When we have both an HTML and a text template, Action Mailer will automatically combine the templates into a multipart email. To make a template specific to our new mailer method, we will name it accordingly and place it in the appropriate view folder, /app/views/user_mailer/new_user_email.html.erb and /app/views/user_mailer/new_user_email.text.erb.  Then we will create the email we want to send when the corresponding method is called.&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc3c5el6akkgi82wp417.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc3c5el6akkgi82wp417.png" alt="Image description"&gt;&lt;/a&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvifatijo6stapvl3k06.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvifatijo6stapvl3k06.png" alt="Image description"&gt;&lt;/a&gt;Now, when our #new_user_email method is called from our UserMailer, rails knows to utilize the view in the views/user_mailer folder that is called new_user_email.html.erb and new_user_email.text.erb.&lt;/p&gt;
&lt;h1&gt;
  
  
  Calling the Mailer
&lt;/h1&gt;

&lt;p&gt;Now that we have our mailer, a mailer method, and a mailer view for that method, all we have to do is call  the mailer. We can do this from inside any controller, and for our #new_user_email method, we'll call it from inside the #create method used to make a new user.&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe18inta4e8flqzqui9ag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe18inta4e8flqzqui9ag.png" alt="Image description"&gt;&lt;/a&gt;In order for our mailer to have access to user variables, we pass them down as params using #with. Since our #new_user_email method utilizes the @firstname and @email attributes, we must pass them through params. Then, we specify which method we'd like to call from our UserMailer, in this case #new_user_email.  Finally, we can utilize #deliver_now or #deliver_later to declare when we want the mailer method to be called. When a new user is created with the #create method, the mailer will be called with the relevant attributes being passed down, and an email will be sent using that method's view. Notice we can even utilize the variables &lt;em&gt;inside&lt;/em&gt; the view if we receive them as instance variables from the controller.  This helps customize each email with whatever unique information gets passed through the params hash.&lt;br&gt;
For a more detailed list of everything offered by the Action Mailer, including how to set attachments and other ways to configure your mailer settings, &lt;a href="https://guides.rubyonrails.org/action_mailer_basics.html#complete-list-of-action-mailer-methods" rel="noopener noreferrer"&gt;https://guides.rubyonrails.org/action_mailer_basics.html#complete-list-of-action-mailer-methods&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Action Mailer for Gmail
&lt;/h1&gt;

&lt;p&gt;In order to get Action Mailer correctly configured for your specified :from email address, there are various settings that can be adjusted to make the mailer work. Here I will provide configuration settings for a personal gmail account. The settings are accessed using config.action_mailer, and configuration settings are best placed in your config/environments folder. &lt;/p&gt;
&lt;h2&gt;
  
  
  Configuration settings
&lt;/h2&gt;

&lt;p&gt;For gmail,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  config.action_mailer.delivery_method = :smtp
  host = 'localhost:3000'
  config.action_mailer.default_url_options = { :host =&amp;gt; 'localhost:3000', protocol: 'http' }
  config.action_mailer.smtp_settings = {
    address:              'smtp.gmail.com',
    port:                 587,
    user_name:            `&amp;lt;gmail_username&amp;gt;`,
    password:             `&amp;lt;gmail_password&amp;gt;`,
    authentication:       'plain',
    enable_starttls_auto: true
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, the delivery method must be specified as :smtp.  The port does not need to be adjusted, and you can set your host server to your local machine if that's what you're using.  Most importantly, you need to provide a username and password for the email account.  If your email uses two-factor authentication, go to gmail -&amp;gt; manage your google account -&amp;gt; security -&amp;gt; 2-step verification -&amp;gt;  app passwords, and select a new app and device and click "generate" to create a password to bypass the two-factor authentication.  Your username will still be the email address you want to use, but the password will be this newly generated string.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety
&lt;/h2&gt;

&lt;p&gt;If you don't want to end up the victim of a password scraper when you accidentally push up your credentials to git, allowing your personal email to be hijacked into a german spam bot (speaking from experience), you need to implement some precautions to your code.  First, I recommend testing with a new email address, just in case.  Second, we need to save our credentials within environment files so they aren't plain to read.  To do this, place the following in your application.rb file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config.before_configuration do
   env_file = File.join(Rails.root, 'config', 'local_env.yml')
   YAML.load(File.open(env_file)).each do |key, value|
     ENV[key.to_s] = value
   end if File.exists?(env_file)
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows variables to be accessed from another file, in this case 'local_env.yml'.  Now, create that file, and inside you can save your credentials.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmnwo4zkozr1cn24bo0mf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmnwo4zkozr1cn24bo0mf.png" alt="Image description"&gt;&lt;/a&gt;Now we can access these new key/value pairs else-where in our set up files. To access our variables, we'll utilize ENV[key] in our credentials object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config.action_mailer.smtp_settings = {
    address:              'smtp.gmail.com',
    port:                 587,
    user_name:            ENV["EMAIL"],
    password:             ENV["EMAILPASSWORD"],
    authentication:       'plain',
    enable_starttls_auto: true
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, in order to keep the identities of these variables hidden, we will add /config/local_env.yml to our .gitignore file. When we push our project up to git, no one will be able to access our email and password!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I hope this was helpful in getting your Action Mailer up and running.  There are many uses for this tool, and it can really add some extra interactivity into a web app or other project.  Don't forget to keep any credentials/passwords safe and hidden.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>actionmailer</category>
    </item>
    <item>
      <title>Active Record Validations</title>
      <dc:creator>jhalfman</dc:creator>
      <pubDate>Wed, 01 Feb 2023 15:43:54 +0000</pubDate>
      <link>https://forem.com/jhalfman/active-record-validations-58j5</link>
      <guid>https://forem.com/jhalfman/active-record-validations-58j5</guid>
      <description>&lt;h2&gt;
  
  
  What are Active Record Validations?
&lt;/h2&gt;

&lt;p&gt;When creating databases, we can create rules for our models when running migrations--these rules will always be run when interacting with the database.  Alternatively, Active Record allows us to specify rules to be checked only when we are saving data to our databases.  These rules are called validations, and they are called any time the database is altered.  The validations are defined in our model files, and they are essential in preventing bad data from being saved to our databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do we get validations?
&lt;/h2&gt;

&lt;p&gt;Active Record provides us with some helper methods by inheriting them from ActiveRecord::Base.  The main method is #validates, which is utilized in a model and along with an attribute to be validated  and the way to validate that attribute.  We can also utilize #validate (without the 's') to write our own custom validations, which will be highlighted later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5g9onsttqqijv3nt7sl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5g9onsttqqijv3nt7sl.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4d6cn75pj94u405dawid.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4d6cn75pj94u405dawid.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What triggers validation?
&lt;/h2&gt;

&lt;p&gt;To prevent bad date from entering the database, Active Record runs our validations before any database activity. This means validations are run before objects are created, saved, or updated using the #create, #save, and #update methods, respectively.  The only way to run validations without causing database activity is with the #valid? method.  The #valid? method can be called on an object and will return true if no errors are found in the object and false if not. Validations are &lt;em&gt;not&lt;/em&gt; run when simply instantiating a new object &lt;strong&gt;without&lt;/strong&gt; saving to the database using the #new method.  There are several other methods that skip validations and therefore must be used with caution.  Some examples of these methods are #insert, #decrement!, and #update_column.  The validations can be bypassed in the #save method by passing validate: false as an argument (this is also a risky technique).&lt;/p&gt;

&lt;p&gt;The following Person class has a name:string and age:integer, and the validation specifies that the name attribute must be present, using &lt;code&gt;validates :name, presence: true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftg7s7bm1np2r9lxca93u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftg7s7bm1np2r9lxca93u.png" alt="Image description"&gt;&lt;/a&gt;As you can see, we are allowed to use #new to make a new Person object, even though the name attribute is not present.  However, when #save is attempted, the record is not saved.  When checking the new Person with #valid?, we see that the method returns false.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgzoysvq3sd1i4smlrzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgzoysvq3sd1i4smlrzs.png" alt="Image description"&gt;&lt;/a&gt;Here, #create is attempted while still missing the required :name attribute.  We can see that the new object has not been created (:id is returned as nil), and #valid? returns false.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7yyi9o6ifniedcqxhew6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7yyi9o6ifniedcqxhew6.png" alt="Image description"&gt;&lt;/a&gt;Finally, a valid Person is created, and #valid? returns true.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation success and failure
&lt;/h2&gt;

&lt;p&gt;If a database method is called and all validations are successful, the method will execute successfully (an object will either be created/saved to the database or updated appropriately). As expected, if the validations fail, Active Record prevents the bad data from being stored! Just what we wanted--but how do we know what happened, and how would we show the user that submitted the incompatible data? Lucky for us, Active Record communicates this to us, too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation errors
&lt;/h2&gt;

&lt;p&gt;When a validation fails, Active Record adds an error to the #errors instance method. All errors can be accessed by calling errors.messages on an instance of a model, and errors of specific attributes can be accessed by calling #errors with a specific attribute (errors[:attribute]). We can also use errors.full_messages for an array of errors that are formatted for clearer rendering to a front-end user.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2d6q1ff28f95mel04ero.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2d6q1ff28f95mel04ero.png" alt="Image description"&gt;&lt;/a&gt;A validation was added to the person model to require numbers for the :age attribute, &lt;code&gt;validates :age, numericality: true&lt;/code&gt;. We can view the default error messages by accessing #errors on the instance of the class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8ut1uocmkx04v3t0n9h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8ut1uocmkx04v3t0n9h.png" alt="Image description"&gt;&lt;/a&gt;#errors.full_messages formats the message by combining the attribute name and the corresponding message into one string.&lt;/p&gt;

&lt;h2&gt;
  
  
  Throwing Exceptions
&lt;/h2&gt;

&lt;p&gt;Aside from adding an error message, Active Record will not do anything else for us unless we ask.  This is done by adding a &lt;code&gt;!&lt;/code&gt; to the end of the database method: #create!, #update!, #save!.  This will tell Active Record to also raise an exception when the validation fails.  We can then rescue the error if it is useful to our control flow.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff4s284ylmx1njk03wkiz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff4s284ylmx1njk03wkiz.png" alt="Image description"&gt;&lt;/a&gt;The RecordInvalid exception can be rescued and used to send the user error messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation helpers
&lt;/h2&gt;

&lt;p&gt;Some of the most commonly used validations are supplied for us by Active Record.  After typing &lt;code&gt;validates :attribute&lt;/code&gt; in a model, we can utilize these helpers on the same line.  The helpers can all be declared with the :on and :message values. The :on option accepts :create and :update and specifies when a validation is called.  The :message option allows you to create your own custom error message instead of the default message provided when a validation is failed.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxfnwel5256a9jw17fj3n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxfnwel5256a9jw17fj3n.png" alt="Image description"&gt;&lt;/a&gt;This Person model would require a value for :name only when using #create, and the message for an invalid age has been customized!&lt;/p&gt;

&lt;p&gt;Here is a list of common validation helpers provided by rubyonrails.org, with a few examples provided for some of them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;acceptance&lt;/li&gt;
&lt;li&gt;validates_associated&lt;/li&gt;
&lt;li&gt;confirmation&lt;/li&gt;
&lt;li&gt;comparison&lt;/li&gt;
&lt;li&gt;exclusion&lt;/li&gt;
&lt;li&gt;format&lt;/li&gt;
&lt;li&gt;inclusion&lt;/li&gt;
&lt;li&gt;length&lt;/li&gt;
&lt;li&gt;numericality&lt;/li&gt;
&lt;li&gt;presence&lt;/li&gt;
&lt;li&gt;absence&lt;/li&gt;
&lt;li&gt;uniqueness&lt;/li&gt;
&lt;li&gt;validates_with&lt;/li&gt;
&lt;li&gt;validates_each&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  uniqueness
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;uniqueness: true&lt;/code&gt; validates if a value exists in the database before the object gets saved.  This can also be used along with the :scope option to limit the uniqueness check to a different attribute.&lt;/p&gt;

&lt;h3&gt;
  
  
  presence/absence
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;presence: true&lt;/code&gt; is a simple way to require that an attribute is not blank.  If the value is nil or a blank string, the validation fails. &lt;code&gt;absence: true&lt;/code&gt; does the opposite, checking if the attribute is nil or blank.&lt;/p&gt;

&lt;h3&gt;
  
  
  numericality
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;numericality: true&lt;/code&gt; verifies that an attribute is only using numeric values.  This validation can also be used with a series of additional constraints to further specify what sort of value is acceptable.  A few of these are: :greater_than requires the value to be greater than the defined value; :odd/:even can be set to true to specify a value must be odd or even; :in checks that the value exists in the provided range.&lt;/p&gt;

&lt;h3&gt;
  
  
  exclusion
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;exclusion: {in: }&lt;/code&gt; accepts a set of values that are prohibited from being used in the specified attribute.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqtq4rek6jmg9t82h7hz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqtq4rek6jmg9t82h7hz.png" alt="Image description"&gt;&lt;/a&gt;Here is an attempt to create a Person with a reserved name, and an age that is neither greater than the specified value nor odd.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom validation
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, we can also use #validate to create our own custom validation.  #validate is used by defining a separate function within the model to perform an action, and then calling validate :custom_validation. When performing a validation check, Active Record looks to see if there are any error messages in the errors collection.  Using this, we can add an error when our custom validation fails in order to cause #valid? to return false.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykdweozcohcdctduetvj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykdweozcohcdctduetvj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifawhrij3pzljulakpnt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifawhrij3pzljulakpnt.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
This shows a custom method that checks to see if :name is in all caps. If it is, an error message is added which causes the validation to fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Use
&lt;/h2&gt;

&lt;p&gt;There are a huge amount of ways to continue to utilize the validations capabilities provided by Active Record.  The methods can be customized and specialized to meet an endless amount of needs.  Visit &lt;a href="https://guides.rubyonrails.org/active_record_validations.html" rel="noopener noreferrer"&gt;https://guides.rubyonrails.org/active_record_validations.html&lt;/a&gt; for full documentation on active record validations, and for further examples of ways to utilize the tool.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>activerecord</category>
    </item>
    <item>
      <title>Server Routing using Sinatra</title>
      <dc:creator>jhalfman</dc:creator>
      <pubDate>Sun, 30 Oct 2022 20:35:03 +0000</pubDate>
      <link>https://forem.com/jhalfman/server-routing-using-sinatra-32i8</link>
      <guid>https://forem.com/jhalfman/server-routing-using-sinatra-32i8</guid>
      <description>&lt;h2&gt;
  
  
  What is Sinatra?
&lt;/h2&gt;

&lt;p&gt;Sinatra is a DSL, or "domain-specific language," specifically utilized in Ruby for creating web applications.  It runs on Rack, and is a light framework intended to make database queries simple with some intuitive, built-in methods.  Using Sinatra methods, we can create the logic that is implemented when requests are made to a Sinatra server.  This includes defining get, post, patch, and delete fetch requests, along with some other options such as options, link, and unlink.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does Sinatra routing look like?
&lt;/h3&gt;

&lt;p&gt;Sinatra routes are written with a ruby block beginning with the request method, the specified route, and then the code block to be executed.  A very simple get request would be written like this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uBhRbsFv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vhc1ly6mi0q7wg2s10fr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uBhRbsFv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vhc1ly6mi0q7wg2s10fr.png" alt="Image description" width="414" height="154"&gt;&lt;/a&gt;&lt;br&gt;
When visiting this route in our web browser, we see this: &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eRoXqv9Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iogfc749shoesx3spk10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eRoXqv9Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iogfc749shoesx3spk10.png" alt="Image description" width="423" height="85"&gt;&lt;/a&gt;&lt;br&gt;
What's happening here is pretty straight-forward: by visiting the route 'localhost:9292/getexample', we are making a get request to our Sinatra server, and we have already told our server what to do!  When a get request is made to this route, the block statement returns a string, 'This is a simple get request'.  Then, our browser displays the content.  Pretty easy.&lt;/p&gt;

&lt;p&gt;Routing using other fetch requests is just as simple.  We start the code with the expected fetch method type, then define the route, then write the code for the server to execute, determining what response we'd like to be sent back to the client (the maker of the request). Here's what some other route blocks might look like: &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q_17DDIt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hrtgo826q1o7o2dz7pak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q_17DDIt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hrtgo826q1o7o2dz7pak.png" alt="Image description" width="579" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Parameters using params hash
&lt;/h3&gt;

&lt;p&gt;You may have noticed in the previous example the ':id' part of the request route.  This is an intro into how we can spice up our routing a bit and make our requests a little more dynamic.  Remember, when we write our routes, we want to try our best to maintain RESTful practices.  In this case, '/:id' should be utilized when viewing a specific instance of a class or group.&lt;/p&gt;

&lt;p&gt;These are called named parameters, and the variable name gets saved in a special object called the params hash.  Using our previous routing examples, here is how to call the params has, and what it looks like when sent back to the client (note: the .to_json method automatically converts data to a json format, helping package information in a readable format before sending it back to the web browser): &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Yu-2L2cv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/76oxn5ttx22hkmuox37i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Yu-2L2cv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/76oxn5ttx22hkmuox37i.png" alt="Image description" width="229" height="59"&gt;&lt;/a&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KOea6ucM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r2r6jxng0x6g74l1fsj6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KOea6ucM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r2r6jxng0x6g74l1fsj6.png" alt="Image description" width="361" height="74"&gt;&lt;/a&gt;&lt;br&gt;
In our sinatra server, we are declaring a route of "/examples/:id", and whatever follows the "/examples/" part of the route is saved in the params hash, within our named parameter :id.  By sending the params hash back to the client, we can see that our id number has been saved in the params hash, and would be accessible via params[:id].  Sinatra is capable of accepting multiple parameters from the route using different named parameters:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j8Ttd8sz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ysk6464yobvqv9k93aop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j8Ttd8sz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ysk6464yobvqv9k93aop.png" alt="Image description" width="333" height="70"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9zsZGVZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lycumh8een2dtj85gr1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9zsZGVZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lycumh8een2dtj85gr1.png" alt="Image description" width="510" height="133"&gt;&lt;/a&gt;&lt;br&gt;
By declaring an :id, :name, and :date parameter, we can save all of those values from the route into our params hash. Since params is just a ruby hash, we can access whatever value we want by calling the parameter name using bracket notation, e.g. params[:name], which would give us "Robert". We also have access to a wildcard option in our routing called a splat parameter.  By using a * in the route name, we can be a little more vague in naming our parameters: &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9hNXMN0m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ytsdk18z4xs2521dbv2f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9hNXMN0m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ytsdk18z4xs2521dbv2f.png" alt="Image description" width="239" height="65"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s51qzdhG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3wb57lbuk8nhts0wlg8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s51qzdhG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3wb57lbuk8nhts0wlg8a.png" alt="Image description" width="561" height="127"&gt;&lt;/a&gt;&lt;br&gt;
The * saves all matching patterns to the :splat parameter, which has an array of all of the wildcard values.&lt;/p&gt;

&lt;p&gt;It is worth noting that sinatra will execute the first route that matches the received route, and that an ending '/' can make a route unique, e.g. '/example/' !== '/example'.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query Parameters
&lt;/h3&gt;

&lt;p&gt;Another way to utilize the params hash is through query parameters, which is similar to the previously mentioned routing parameters, but are used within a single route.  This can be useful when accepting search criteria or filter options.  A request to get a list of food items, but only vegetarian options, is still recognized by the server like this: &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y7Qn5bFD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oi4hvm0u1zbfnu8379kc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y7Qn5bFD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oi4hvm0u1zbfnu8379kc.png" alt="Image description" width="218" height="73"&gt;&lt;/a&gt;&lt;br&gt;
This route, however, matches '/food' as well as '/food?AnythingHere'.  To add a vegetarian filter to our search, the client sends a get request to '/food?diet=vegetarian', and our server does the work of adding that information to the params hash.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EnB3Zu64--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pqfvgtvzn466m8ld7t8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EnB3Zu64--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pqfvgtvzn466m8ld7t8.png" alt="Image description" width="435" height="77"&gt;&lt;/a&gt;&lt;br&gt;
We can combine our query parameters with our named parameters to store a lot of information in our params hash, and it only requires a single route on the server side:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s9PPBgO3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8es5wxx3b7mfj4gv4h5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s9PPBgO3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8es5wxx3b7mfj4gv4h5.png" alt="Image description" width="233" height="75"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1mXHdZtw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6tofuo1vhqku7pz1ratg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1mXHdZtw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6tofuo1vhqku7pz1ratg.png" alt="Image description" width="575" height="89"&gt;&lt;/a&gt;&lt;br&gt;
The params hash is very versatile and can be utilized to store and access a lot of information, helping make our server very dynamic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrap Up
&lt;/h3&gt;

&lt;p&gt;Routing can get a lot more complicated, and Sinatra gives us access to a lot of other methods and ways to receive requests.  We can define conditions for our routes, use regular expressions, and even have optional parameters.  The params hash is also what sinatra uses when receiving a post request.  All of the key/object pairs in a post request are saved into the params hash so that they can be utilized in the block statement for the post request.  That's a lot of use for one hash!&lt;/p&gt;

</description>
      <category>react</category>
      <category>sinatra</category>
      <category>javascript</category>
      <category>activerecord</category>
    </item>
    <item>
      <title>Custom React Hooks</title>
      <dc:creator>jhalfman</dc:creator>
      <pubDate>Mon, 15 Aug 2022 23:04:00 +0000</pubDate>
      <link>https://forem.com/jhalfman/phase-2-blog-ol8</link>
      <guid>https://forem.com/jhalfman/phase-2-blog-ol8</guid>
      <description>&lt;h1&gt;
  
  
  Where did Hooks come from?
&lt;/h1&gt;

&lt;p&gt;Initially, React relied on class components for things like state and sharing logic between components, causing complicated component hierarchies and confusing prop logic.  To alleviate these issues, React introduced hooks at the end of 2018. &lt;iframe width="710" height="399" src="https://www.youtube.com/embed/dpw9EHDh2bM?start=1"&gt;
&lt;/iframe&gt;
 There are some very common hooks built in, such as useState and useEffect, but React also provides the functionality to create one's own custom hooks.&lt;/p&gt;
&lt;h1&gt;
  
  
  A break from class
&lt;/h1&gt;

&lt;p&gt;In order to prevent the need for classes, hooks allow the user to "hook" into React state from your React function components.  Hooks always start with "use" and follow two main functional rules.  Hooks should not be called from inside loops or conditionals; they should be kept at the top level.  They should also only be called from React function components, not regular JS functions. The only other acceptable place to call a hook is from a custom hook component.&lt;/p&gt;
&lt;h1&gt;
  
  
  Build your own
&lt;/h1&gt;

&lt;p&gt;As mentioned, the convention for a custom hook is "useSOMETHING." Any time you want to reuse stateful logic between multiple components, you have a good opportunity to create a custom hook.  To start, create a file for our new hook just like for a function component, something like src/hooks/useBlogExample.js.  Creating the function looks just like a normal component, except it's called "use____" instead of the normal capitalization of the first letter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function useBlogExample() {
  //DO SOMETHING HERE
}

export default useBlogExample;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our custom hook can provide a simple action that any function could do, like simply printing something to the console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from 'react';

function useBlogExample() {
  console.log("THIS IS FROM A CUSTOM HOOK")
}

export default useBlogExample;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To call this hook, we would just have to import it and invoke it just like any other function or hook &lt;code&gt;useBlogExample()&lt;/code&gt;.  This isn't very useful, though, since a console.log doesn't need a hook to utilize it. Remember, custom hooks are the one other place that hooks can be called aside from React function components, so let's write a hook that utilizes useState and useEffect.  To start, we can import useState and useEffect into our custom hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from 'react';

function useBlogExample() {
  //DO SOMETHING HERE
}

export default useBlogExample;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within the custom hook, state and useEffect work the same way as in a React component.  We can set state within the hook, and we can call useEffect for something like an API fetch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from 'react';

function useBlogExample() {
  const [state, setState] = useState(null);

  useEffect(() =&amp;gt; {
    fetch("http://localhost:3000/items")
    .then(resp =&amp;gt; resp.json())
    .then(data =&amp;gt; setState(data))
  }, []);

export default useBlogExample;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As it is currently, this hook will only adjust its own state to the data returned from the API fetch.  If we want data to actually come out of this hook (and we do!), we need to simply return the data, just like from a regular function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from 'react';

function useBlogExample() {
  const [state, setState] = useState(null);

  useEffect(() =&amp;gt; {
    fetch("http://localhost:3000/items")
    .then(resp =&amp;gt; resp.json())
    .then(data =&amp;gt; setState(data))
  }, []);

  return {state: state};

export default useBlogExample;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We return an object with the state variable so that it can be destructured when called in a component. &lt;code&gt;const {data} = useBlogExample();&lt;/code&gt;&lt;br&gt;
Now, every time we call useBlogExample, the hook will return for use the results of that API call.  This is useful, but is likely not very versatile.  It is not likely that two components would be making the exact same fetch call.  Perhaps two components are making fetch calls to two locations in the database.  We can adapt our hook to be accepting of varying urls!  We just have to allow the hook to accept a parameter, and utilize the parameter in the url of the fetch call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from 'react';

function useBlogExample(location) {
  const [state, setState] = useState(null);

  useEffect(() =&amp;gt; {
    fetch(`http://localhost:3000/${location}`)
    .then(resp =&amp;gt; resp.json())
    .then(data =&amp;gt; setState(data))
  }, []);

  return {state: state};

export default useBlogExample;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, one component could call our hook to get a response from one endpoint, and a separate hook could make a call to a different location! Perhaps we want to make calls from localhost:3000/names and from /professions.  In one component, we could call &lt;code&gt;{state} = useBlogExample("names")&lt;/code&gt; and from the other component &lt;code&gt;{state} = useBlogExample("professions")&lt;/code&gt;.  If using a hook to return differing types of data, make sure to keep the variable name vague enough to describe both possibilities.  If you'd like, you can rename the data to a more specific variable when you destructure it.&lt;/p&gt;

&lt;p&gt;And that's it! Custom hooks are essentially just reusable functions, but they can utilize state and other hooks to clean up some redundancy among your React components.  They have the added bonus of being used by any new components that you create as your application grows.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>HTML forms and submit events</title>
      <dc:creator>jhalfman</dc:creator>
      <pubDate>Mon, 20 Jun 2022 23:17:30 +0000</pubDate>
      <link>https://forem.com/jhalfman/html-forms-and-submit-events-1418</link>
      <guid>https://forem.com/jhalfman/html-forms-and-submit-events-1418</guid>
      <description>&lt;h2&gt;
  
  
  HTML Forms
&lt;/h2&gt;

&lt;p&gt;The html form element is frequently used on the web and can support a lot of variation.  Functionally, a form is used to obtain user input, and is represented with the &amp;lt;form&amp;gt; tag.  Within the form, there can be one or more of the following types of elements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&amp;lt;input&amp;gt; is a very common and versatile form element.  It has a default type of "text" but has over 20 different type options. 
I will be focusing on the &amp;lt;input&amp;gt; type.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&amp;lt;textarea&amp;gt; is a text input that allows for multiple lines of text&lt;/li&gt;
&lt;li&gt;&amp;lt;button&amp;gt; is a standard, clickable button&lt;/li&gt;
&lt;li&gt;&amp;lt;select&amp;gt; provides a drop-down list of options&lt;/li&gt;
&lt;li&gt;&amp;lt;option&amp;gt; is used to define the options inside of other form elements, such as inside a  list&lt;/li&gt;
&lt;li&gt;&amp;lt;optgroup&amp;gt; is also used in  lists to group related options within the list&lt;/li&gt;
&lt;li&gt;&amp;lt;fieldset&amp;gt; is another organizational tool, used to group related elements within a form&lt;/li&gt;
&lt;li&gt;&amp;lt;label&amp;gt; sets a label using a "for" attribute that matches the id of a related form element.  This can be useful for screen readers, and increases overall readability&lt;/li&gt;
&lt;li&gt;&amp;lt;output&amp;gt; is used to compute and display the result of a specified calculation performed on other elements&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a standard form element with a text input, a textarea, and a button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;form&amp;gt;
  &amp;lt;input type="text" placeholder="Input 1" style="margin-bottom: 5px"&amp;gt;
  &amp;lt;br&amp;gt;
  &amp;lt;textarea rows="3" cols= "30"&amp;gt;Example text 1&amp;lt;/textarea&amp;gt;
  &amp;lt;br&amp;gt;
  &amp;lt;button type="button"&amp;gt;Button&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yzHe3OWG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sus6wvy81ujig6x13ujl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yzHe3OWG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sus6wvy81ujig6x13ujl.png" alt="Displays one text input, one text area, one button" width="313" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Input types
&lt;/h2&gt;

&lt;p&gt;There is a large amount of input types.  The default is type="text", but any of the following can be set:&lt;br&gt;
button, checkbox, color, data, datetime-local, email, file, hidden, image, month, number, password, radio, range, reset, search, submit, tel, text, time, url, week.&lt;br&gt;
These come with a wide range of features, such as a password field keeping entries hidden, or type email requiring proper email format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;form id="form1"&amp;gt;
  &amp;lt;label for="username"&amp;gt;Username:&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;
  &amp;lt;input type="text" id="username"&amp;gt;&amp;lt;br&amp;gt;
  &amp;lt;label for="pwd"&amp;gt;Password:&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;
  &amp;lt;input type="password" id="pwd"&amp;gt;&amp;lt;br&amp;gt;
  &amp;lt;label for="email"&amp;gt;Email:&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;
  &amp;lt;input type="email" id="email" placeholder="Email"&amp;gt;
  &amp;lt;input type="submit" id="submit"&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--30xoup1v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/osvb8jpsi1gvt11motll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--30xoup1v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/osvb8jpsi1gvt11motll.png" alt="Displays form with username field, hidden password entry, and email with error &amp;quot;please include an '@' in the email address" width="698" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Several things can happen to the information when the form is submitted. The form tag can take an action attribute with a URL value. When the form is submitted, the data will be sent to the specified URL: &lt;code&gt;&amp;lt;form action="/server_url.php method="get"&amp;gt;&lt;/code&gt;&lt;br&gt;
Alternatively, if the information will be utilized immediately, the submission can be linked to an event listener.&lt;/p&gt;
&lt;h2&gt;
  
  
  Submit Events
&lt;/h2&gt;

&lt;p&gt;Submit events on forms are used to collect the user input from the form and use it elsewhere.  Usually, this is done when an input type="submit" is clicked or a button type="submit" is clicked, but it can also be triggered by pressing "enter" &lt;br&gt;
while editing a form field. On the previous form, the submit event would look like this: &lt;code&gt;document.getElementById("form1").addEventListener("submit",(event) =&amp;gt; console.log("Successful submission!"))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It is worth noting that a submit event occurs on the entire form, and not just the input button that was pressed.  Further, the event type must be called "submit" and will not provide the same function if there is a "click" event on the submit button.  In the previous example, the entire form is grabbed using the form id "form1", instead of adding the event listener to the form submit button.&lt;/p&gt;

&lt;p&gt;When the submission is triggered, an event object is created.  This event has properties like timestamp, type, and target, among others. If writing javascript to handle data from a submission, the event object data can be used to access the input submissions. It turns out that the event target refers to the entire form, so using the ids of the form elements, the information can be accessed. For example, in the previous form, the username would be accessed with &lt;code&gt;event.target.value&lt;/code&gt;, the password could be accessed with &lt;code&gt;event.pwd.value&lt;/code&gt;, and the email could be accessed with &lt;code&gt;event.email.value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are many default responses from the browser to various events, and one of them is in response to submits.  A browser will submit the form and refresh the page.  This can cause issues with webpage functionality, so sometimes it is necessary to prevent this default behavior. This is done by calling preventDefault() on the submit event. &lt;code&gt;event.preventDefault()&lt;/code&gt; can be used at the start of the event listener callback function to remain on the same page without reloading.&lt;/p&gt;

&lt;p&gt;Because of preventDefault, the user inputs will remain in the form. This can be an issue if you want the form to remain clear for further use. To remedy the lingering information, you can call .reset() on the form element &lt;code&gt;event.target.reset()&lt;/code&gt;. Putting all this together, a submit event to store data in a new object might look like this in javascript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.getElementById("form1").addEventListener("submit", (event) =&amp;gt; {
event.preventDefault();
const formObj = {
username: event.target.username,
password: event.target.pwd,
email: event.target.email
}
event.target.reset();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;At its simplest, the form element takes in user input to be used elsewhere, whether that's through a URL submission or an event listener. There are many different types of form elements, ranging from regular text to drop down menus to buttons, and those elements can also be many different types. When using an event listener, remember to prevent the default behavior if you do not want to refresh the page, and utilize the target property of the event to access submission data.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
