Sunday, 11 June 2017

Allow serialized attributes with unknown keys to be permitted in strong parameters.

Suppose that, we have Attempt model and we have serialized an attribute in attempt.rb like this



class Attempt < ApplicationRecord

 #==== Serializations ==================
   serialize :response

 end


Now, if you are creating attempt through strong parameters in controller -

   
   
Attempt.create(attempts_params)


And you have permitted response attribute in strong parameters like this


 def attempts_params
     params.require(:attempt).permit(:response)
 end


        OR

   

 def attempts_params
     params.require(:attempt).permit(:response => {})
 end


Above strong parameters will save response as nil or blank. In this scenario we have to permit keys of serialized attributes in strong parameter



 def attempts_params
     response_keys = params[:attempt][:response].keys
     params.require(:attempt).permit(response: response_keys)
 end

Saturday, 3 June 2017

Twilio Phone Number authentication with Authy in Ruby on Rails.

Authy is a Twilio service that provides two factor authentication as an API, making it easy to secure users accounts. Using authy services we can authenticate users by their phone number. OTP will be send on phone number and it will be verified at the twilio end.


In Gemfile.

    # Use Authy for sending token
    gem 'authy'
    # Use Twilio to send confirmation message
    gem 'twilio-ruby'

We need an API key for Authy. You can get this from your Twilio account portal. Click the link to access the Authy dashboard.

If you don’t already have an Authy account, this will set one up for you. You will need to verify your email address and set up two factor authentication. Then you can create an application with Authy and this will give you your API key.

Create a new file authy.rb in config/initializers.

In authy.rb


    Authy.api_key = 'api_key'

    Authy.api_uri = 'https://api.authy.com/'

Now, we can start phone verification via sending a sms.

In sessions controller


     def send_otp

         response = Authy::PhoneVerification.start(via: "sms", country_code: 1, phone_number: "111-111-1111")

         render json: {response: response.message}, status: response.code

     end


    def verify_otp

        response = Authy::PhoneVerification.check(verification_code: "1234", country_code: 1, phone_number: "111-111-1111")

        if response.ok?

              # verification was successful

            end       

    end

In routes.rb


    resources :sessions do

        collection do

          post :send_otp

          post :verify_otp

        end

    end

Friday, 26 May 2017

Newsletter Subscription in Shopify and connecting it to HubSpot

If you need newsletter subscription in your Shopify e-commerce, first you have to select the theme in which newsletter sign up form is available. As many Shopify themes provides a basic newsletter sign up form in the footer or right column.

But, It does nothing when you click submit button because of the newsletter sign up form is not connected to the Shopify backend.

For proper working We have to replace email signup form with this code -



{% form 'customer' %}
        {{ form.errors | default_errors }}
        {% if form.posted_successfully? %}
          <p class="form--success">{{ 'general.newsletter_form.confirmation' | t }}</p>
        {% else %}
          <div class="input-group">
            <input type="hidden" name="contact[tags]" value="newsletter">
            <label for="Email" class="newsletter__label label--hidden">{{ 'general.newsletter_form.email_placeholder' | t }}</label>
            <input type="email" value="{% if customer %}{{ customer.email }}{% endif %}" placeholder="{{ 'general.newsletter_form.email_placeholder' | t }}" name="contact[email]" id="Email" class="input-group__field newsletter__input" autocorrect="off" autocapitalize="off">
            <span class="input-group__btn">
              <button type="submit" class="btn newsletter__submit" name="commit" id="Subscribe">
                <span class="newsletter__submit-text--large">{{ 'general.newsletter_form.submit' | t }}</span>
              </button>
            </span>
          </div>
        {% endif %}
 {% endform %}

When properly connected, a newsletter sign up will be fed to HubSpot via Hubshoply and show as a conversion event. You can get it in customers section of Shopify and contacts in HubSpot.


Friday, 19 May 2017

Categorized words according to parts of speech from english sentence in Ruby

In the English language, words can be considered as the smallest elements that have distinctive meanings. Based on their use and functions, words are categorized into several types or parts of speech.

In this blog we will define and examples for major parts of speech from English sentence with using ruby gem engtagger .



 require 'rubygems'
 require 'engtagger'


 # Initialize a parser object
 tgr = EngTagger.new

 # Sample text
 text = "Ruby is an expressive, dynamic programming language."

 # Add part-of-speech tags to text
 tagged = tgr.add_tags(text)

 # Get all nouns from a tagged output
 nouns = tgr.get_nouns(tagged)

 => {"Ruby"=>1, "programming"=>1, "language"=>1}

 # Get all the adjectives
 adj = tgr.get_adjectives(tagged)

 => {"expressive"=>1, "dynamic"=>1}

 # Get all the verbs
 adj = tgr.get_verbs(tagged)

 => {"is"=>1}
 
 
 
 
 

Thursday, 11 May 2017

Fetch all products from Shopify api



Suppose, If your store contains more than 50 products and you wish to fetch all products from store.

When you call a shopify api's like this -

products = ShopifyAPI::Product.all

Above api will fetch maximum of 50 products but you can use limit parameter to set limit of products in every call of api's like this -

products = ShopifyAPI::Product.find(:all,:params =&gt; {:limit =&gt; 250})

But above api's also returns only 250 products. What if you have more then 250? Can’t you just increase the limit to the total number of products in your catalog to 1000? As simple as it sounds, it doesn’t quite work in that way… Shopify uses a technique called pagination, which basically divides the response to your request into separate memory chunk.

So, we can use pagination technique to fetch all products from shopify -
count = ShopifyAPI::Product.count
       page = 1
       products = []
       while count > 0 do
         products << ShopifyAPI::Product.find(:all, :params => {:page => page})
         count = count - 50
         page = page + 1
       end
 products.flatten!

It will return all products of your shopify store.

Sunday, 7 May 2017

Fetch products from Shopify and create or update metafields with key value of each product with Shopify api's.

Sometime, it becomes essentials to add a customized metafield in product so,we can add some functionality with the help of these metafields.
In this blog, we will fetch products from a store of shopify and create our customized metafield in which we will add pdf file url for each product.

 ############ Required Dependencies ##############


    require 'rubygems'

    require 'shopify_api'



    ############ Shopify Credentials ################


    API_KEY = '846bef1--------------------------'

    PASSWORD = '2e0eed--------------------------'

    SHOPNAME = 'store_name_of_shopify-----------'

    shop_url = "https://#{API_KEY}:#{PASSWORD}@#{SHOPNAME}.myshopify.com/admin"


    ##### Fetch Products and create metafields ######   

    begin

      ShopifyAPI::Base.site = shop_url

      products = ShopifyAPI::Product.all

      products.each do |product|

        metafield = ShopifyAPI::Metafield.new(key:'pdf_url_s3',

                                          namespace: "headerlabs",

                                          value: 'http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-dg.pdf',

                                          value_type: "string")

        product.add_metafield(metafield)

      end

    rescue => e

      puts e.inspect

    end

Now, you can access these metafields in template of product in shopify liquid file

    {% assign headerlabs = product.metafields.headerlabs %}

    {% assign key = 'pdf_url_s3' %}

    <a href={{ headerlabs.pdf_url_s3}} target="_blank" > 

Sunday, 23 April 2017

Update attr_accessor wiithin accepts_nested_attributes_for in Rails


Suppose that we have association like this -

        class Employer < ApplicationRecord
          
          has_one :account
          accepts_nested_attributes_for :account

        end 


and
        class Account < ApplicationRecord

          belongs_to :employer
          attr_accessor :area

        end


In above association account belongs_to employer and has attr_accessor attributes :area.

Now, we have form like this -
        <%= form_for(@employer) do |f| %>
        
            <%= f.fields_for :account do |acc| %>
              <%= acc.file_field :account_number %>        
              <%= acc.file_field :area %>
            <% end %>
        <% end %>


So, we want to update account attributes within employer update method. For this we have to white-list it in employer strong parameter -

In employers controller,

    def update

        if @employer.update(employer_params)

          flash[:notice] = 'Employer updated Successfully'

          redirect_to employer_path

        else

          flash[:notice] = @employer.errors.full_messages.to_sentence

          redirect_to employer_path

        end

      end


    private

      def employer_params
        params.require(:employer).permit(:name, :email, :password, :role, account_attributes: [:id, :account_number, :area])
      end 


From above method it will update attr_accessor attributes only when we will update account_number attributes.

But what if we want only update attr_accessor attributes that is :area. It won't be updated if none of account attributes updating same time.

For updating attr_accessor wiithin accepts_nested_attributes_for we have to do couple of things -

In Account.rb
    

    class Account < ApplicationRecord

        
          belongs_to :employer
          attr_accessor :area


        def new_attr=(a)
          attribute_will_change!(:name)
          self.area = a
        end



    end


and in strong parameters of employers controller -
    def employer_params
      params.require(:employer).permit(:name, :email, :password, :role, account_attributes: [:id, :account_number, :new_attr])
    end