Wednesday, 26 February 2025

Send attachment with mail in rails

 Routes: 

post "/send_email_with_attachment", to: "articles#send_email_with_attachment"

-----------------------------------

Controller:

class ArticlesController < ApplicationController

  def send_email_with_attachment

    email = "arvind@gmail.com"

    attachment = params[:attachment]

    # Save the file temporarily

    file_path = Rails.root.join('tmp', attachment.original_filename)

    File.open(file_path, 'wb') do |file|

      file.write(attachment.read)

    end

    MyMailer.send_email_with_attachment(email, file_path).deliver_now

    # Delete the temporary file after sending the email

    File.delete(file_path) if File.exist?(file_path)

    redirect_to root_path, notice: 'Email sent successfully'

  end

end


--------------------------

Mailer

class MyMailer < ApplicationMailer

  def send_email_with_attachment(email, attachment_path)

    @greeting = "Hi"

    attachments[File.basename(attachment_path)] = File.read(attachment_path)

    mail(to: email, subject: 'Email with Attachment')

  end

end

-------------------------------

View
Form view:

<%= form_tag "/send_email_with_attachment", class: "inline-form", multipart: true do %>
  <%= file_field_tag :attachment %>
  <%= submit_tag 'Send Email' %>
<% end %>

Mailer view:

<h1>My#send_email_with_attachment</h1>

<p>
  <%= @greeting %>, find me in app/views/my_mailer/send_email_with_attachment.html.erb
</p>

----------------------------

Development.rb

config.action_mailer.perform_deliveries = true
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.default_options = {from: 'localhost:3000'}
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address:              'smtp.gmail.com',
    port:                 587,
    domain:               'localhost',
    user_name:            ENV["SMTP_EMAIL"],
    password:             ENV["SMTP_PASSWORD"],
    authentication:       'plain',
    enable_starttls_auto: true
  }


public bucket on AWS s3

 Please visite: https://alex-okorkov.medium.com/how-to-set-up-aws-s3-bucket-on-rails-with-activestorage-d384075ce773

--------------------


Code:

{

    "Version": "2012-10-17",

    "Statement": [

        {

            "Effect": "Allow",

            "Principal": "*",

            "Action": "s3:ListBucket",

            "Resource": "arn:aws:s3:::newlogoimages"

        },

        {

            "Effect": "Allow",

            "Principal": "*",

            "Action": [

                "s3:PutObject",

                "s3:GetObject",

                "s3:DeleteObject"

            ],

            "Resource": "arn:aws:s3:::newlogoimages/*"

        }

    ]

}



Thursday, 9 January 2025

Add nested form in rails 7

 1. Add Gem

gem "nested_form"

Run$ : bundle 
----------------
2. Created new file : app/javascript/js/nested_form.js

rails g nested_form:install
jb ye line run karege to public ke ander >> public/javascript/js/nested_form.js file generate hogi, lekin nested_form.js ka code is directory me add kar dena >>  app/javascript/js/nested_form.js

app/javascript/js/nested_form.js

(function($) {
  window.NestedFormEvents = function() {
    this.addFields = $.proxy(this.addFields, this);
    this.removeFields = $.proxy(this.removeFields, this);
  };

  NestedFormEvents.prototype = {
    addFields: function(e) {
      // Setup
      var link      = e.currentTarget;
      var assoc     = $(link).data('association');                // Name of child
      var blueprint = $('#' + $(link).data('blueprint-id'));
      var content   = blueprint.data('blueprint');                // Fields template

      // Make the context correct by replacing <parents> with the generated ID
      // of each of the parent objects
      var context = ($(link).closest('.fields').closestChild('input, textarea, select').eq(0).attr('name') || '').replace(new RegExp('\[[a-z_]+\]$'), '');

      // context will be something like this for a brand new form:
      // project[tasks_attributes][1255929127459][assignments_attributes][1255929128105]
      // or for an edit form:
      // project[tasks_attributes][0][assignments_attributes][1]
      if (context) {
        var parentNames = context.match(/[a-z_]+_attributes(?=\]\[(new_)?\d+\])/g) || [];
        var parentIds   = context.match(/[0-9]+/g) || [];

        for(var i = 0; i < parentNames.length; i++) {
          if(parentIds[i]) {
            content = content.replace(
              new RegExp('(_' + parentNames[i] + ')_.+?_', 'g'),
              '$1_' + parentIds[i] + '_');

            content = content.replace(
              new RegExp('(\\[' + parentNames[i] + '\\])\\[.+?\\]', 'g'),
              '$1[' + parentIds[i] + ']');
          }
        }
      }

      // Make a unique ID for the new child
      var regexp  = new RegExp('new_' + assoc, 'g');
      var new_id  = this.newId();
      content     = $.trim(content.replace(regexp, new_id));

      var field = this.insertFields(content, assoc, link);
      // bubble up event upto document (through form)
      field
        .trigger({ type: 'nested:fieldAdded', field: field })
        .trigger({ type: 'nested:fieldAdded:' + assoc, field: field });
      return false;
    },
    newId: function() {
      return new Date().getTime();
    },
    insertFields: function(content, assoc, link) {
      var target = $(link).data('target');
      if (target) {
        return $(content).appendTo($(target));
      } else {
        return $(content).insertBefore(link);
      }
    },
    removeFields: function(e) {
      var $link = $(e.currentTarget),
          assoc = $link.data('association'); // Name of child to be removed
      
      var hiddenField = $link.prev('input[type=hidden]');
      hiddenField.val('1');
      
      var field = $link.closest('.fields');
      field.hide();
      
      field
        .trigger({ type: 'nested:fieldRemoved', field: field })
        .trigger({ type: 'nested:fieldRemoved:' + assoc, field: field });
      return false;
    }
  };

  window.nestedFormEvents = new NestedFormEvents();
  $(document)
    .delegate('form a.add_nested_fields',    'click', nestedFormEvents.addFields)
    .delegate('form a.remove_nested_fields', 'click', nestedFormEvents.removeFields);
})(jQuery);

// http://plugins.jquery.com/project/closestChild
/*
 * Copyright 2011, Tobias Lindig
 *
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 */
(function($) {
        $.fn.closestChild = function(selector) {
                // breadth first search for the first matched node
                if (selector && selector != '') {
                        var queue = [];
                        queue.push(this);
                        while(queue.length > 0) {
                                var node = queue.shift();
                                var children = node.children();
                                for(var i = 0; i < children.length; ++i) {
                                        var child = $(children[i]);
                                        if (child.is(selector)) {
                                                return child; //well, we found one
                                        }
                                        queue.push(child);
                                }
                        }
                }
                return $();//nothing found
        };
})(jQuery);

--------------------------------------------
4. config/importmap.rb

# Pin npm packages by running ./bin/importmap

pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin "nested_form", to: "js/nested_form.js"
pin_all_from "app/javascript/controllers", under: "controllers"
pin_all_from "app/javascript/js", under: "js", preload: true

------------------------------------------------
5. app/javascript/application.js

// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "controllers"
import "js/bootstrap.bundle.min"
import "js/simple-datatables"
import "js/quill.min"
import "js/tinymce.min"
import "js/validate"
import "js/main"
import "nested_form";
--------------------------------------------
6. User.rb
has_many :products, dependent: :destroy
  accepts_nested_attributes_for :products, allow_destroy: true
-----------------------------
7. Product.rb
class Product < ApplicationRecord
belongs_to :user
end
------------------------------------------

8. On form
<%= simple_nested_form_for @user, url: user_path(@user), html: { class: 'row g-3', "data-turbo": false } do |f| %>

<div class="col-md-6 mt-4">
         <label class="form-label">Bericht</label>
            <%= f.input :email, input_html: { class: "form-control form-control-sm", rows: 5 }, label: false %>
        </div>

<h3>Products</h3>
  <div id="products">
    <%= f.fields_for :products do |product_form| %>
      <div class="nested-fields">
        <%= product_form.label :name, "Product Name" %>
        <%= product_form.text_field :name %>

        <%= product_form.link_to_remove "Remove" %>
      </div>
    <% end %>
  </div>
        <%= f.link_to_add "Add a products", :products, :data => { :target => "#products" } %>

<% end %>
-------------------------------------------------

9. User controller.rb
def users_params
    params.require(:user).permit(:email, products_attributes: [:id, :name, :_destroy])
  end