Как передать параметры моей модели на рельсы представления?

#ruby-on-rails

Вопрос:

Я пытаюсь создать PDF-файлы в Rails, используя драгоценный камень креветки.Данные для pdf-файла частично жестко закодированы, но некоторые из них должны быть получены из формы rails.

Я создал «Шаблонный» каркас с именем, адресом и идентификатором. Используя креветку, я создал pdf-файл. Он распечатывает PDF-файл без каких-либо проблем. Я хочу передать параметры модели в формате pdf, чтобы, например, написать: «Эта форма предназначена для #{Template.name} который живет по адресу #{Template.address} и имеет идентификатор #{Template.NationalId}», где имя, адрес и NationalId взяты из формы.

Я также хочу обобщить этот метод и сделать это для разных отчетов PDF-файлов, сертификатов и т. Д. Из одного и того же приложения.

Как мне передать эти данные ?

Ниже приведен мой код:

   #Controller
  class TemplatesController < ApplicationController
  before_action :set_template, only: %i[ show edit update destroy ]

def index
  @templates = Template.all

  respond_to do |format|
    format.html
    format.pdf do
      pdf = ReportPdf.new
      send_data pdf.render, filename: 'report.pdf', type: 'application/pdf', 
      disposition: "inline"
    end
  end
end

def create
@template = Template.new(template_params)

respond_to do |format|
  if @template.save
    format.html { redirect_to @template, notice: "Template was successfully created." }
    # format.pdf { render :index, status: :created, location: @template }
    format.json { render :index, status: :created, location: @template }
  else
    format.html { render :new, status: :unprocessable_entity }
    format.json { render json: @template.errors, status: :unprocessable_entity }
  end
end
end

#...lots of other controllers update, destroy etc

private
# Use callbacks to share common setup or constraints between actions.
def set_template
  @template = Template.find(params[:id])
end

# Only allow a list of trusted parameters through.
def template_params
  params.require(:template).permit(:name, :address, :NationalId)
end
end
 

#Мой отчет.pdf. (Вставьте данные в область текстового содержимого)

 class ReportPdf < Prawn::Document
def initialize
    super()
    header
    text_content
end

def header
    #This inserts an image in the pdf file and sets the size of the image
    image "#{Rails.root}/app/assets/images/logo.jpg", width: 230, height: 75
  end

  def text_content
    # The cursor for inserting content starts on the top left of the page. Here we move it down a little to create more space between the text and the image inserted above
    y_position = cursor - 50

    # The bounding_box takes the x and y coordinates for positioning its content and some options to style it
    bounding_box([0, y_position], :width => 270, :height => 300) do
      text "**Pass params here**", size: 15, style: :bold
      text "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ."
    end

    bounding_box([300, y_position], :width => 270, :height => 300) do
      text "Duis vel", size: 15, style: :bold
      text "Duis vel tortor elementum, ultrices tortor vel, accumsan dui. Nullam in dolor rutrum, gravida turpis eu, vestibulum lectus. Pellentesque aliquet dignissim justo ut fringilla. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut venenatis massa non eros venenatis aliquet. Suspendisse potenti. Mauris sed tincidunt mauris, et vulputate risus. Aliquam eget nibh at erat dignissim aliquam non et risus. Fusce mattis neque id diam pulvinar, fermentum luctus enim porttitor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos."
    end
    
    end

  end
 

Форма

  <%= form_with(model: template, local: true) do |form| %>
   <% if template.errors.any? %>
     <div id="error_explanation">
       <h2><%= pluralize(template.errors.count, "error") %> prohibited this template 
       from being saved:</h2>

       <ul>
         <% template.errors.full_messages.each do |message| %>
           <li><%= message %></li>
         <% end %>
       </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :address %>
    <%= form.text_field :address %>
  </div>

  <div class="field">
    <%= form.label :address %>
    <%= form.text_field :address %>
  </div>

  <div class="field">
    <%= form.label :NationalId %>
    <%= form.text_field :NationalId %>
  </div>

  <div class="actions">
    <%= form.submit %>
    </div>
  <% end %>
 

Комментарии:

1. В его инициализаторе и интерполируйте текстовое содержимое так, как вы уже есть в заголовке?

Ответ №1:

Вы можете передать параметры в метод инициализатора:

 class ReportPdf < Prawn::Document
  attr_reader :template
  # You should keep the initialzer signature of the super method
  def initialize(templates:, **options, amp;block)
    @templates = templates
    # the super method still uses the old style initialize(options = {}, amp;block)
    # instead of keyword arguments
    super(options, amp;block) 
    header
    text_content
  end

  def text_content
  # The cursor for inserting content starts on the top left of the page. Here we move it down a little to create more space between the text and the image inserted above
    y_position = cursor - 50

    # The bounding_box takes the x and y coordinates for positioning its content and some options to style it
    bounding_box([0, y_position], :width => 270, :height => 300) do
      text "**Pass params here**", size: 15, style: :bold
      text "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ."
    end

    templates.each do |template|
      bounding_box([300, y_position], :width => 270, :height => 300) do
        text "Duis vel", size: 15, style: :bold  
        # @todo NationalId should be named national_id 
        #  change the name of the column or setup an alias if you cannot
        text "This form is for #{template.name} who lives at #{template.address} 
        and has an id of #{template.NationalId}"
      end
    end
  end
end
 

Здесь мы используем обязательный аргумент ключевого слова. Вы также можете использовать позиционный аргумент или сделать его необязательным:

 # postitional argument
def initialize(templates, **options, amp;block)

# optional keyword argument
def initialize(templates: [], **options, amp;block)
 

Преимущество аргументов с ключевыми словами заключается в ясности и в том, что вам не нужно запоминать порядок аргументов.

 def index
  @templates = Template.all

  respond_to do |format|
    format.html
    format.pdf do
      pdf = ReportPdf.new(templates: @templates)
      send_data pdf.render, filename: 'report.pdf', type: 'application/pdf', 
      disposition: "inline"
    end
  end
end
 

Ответ №2:

Когда вы создаете свой PDF-файл с помощью класса ReportPdf (using pdf = ReportPdf.new ), вы можете передавать любые параметры, которые хотите. Вам просто нужно добавить соответствующие параметры к initialize методу в ReportPdf классе. Так, например:

 pdf = ReportPdf.new(@name, @address)
 
 def initialize(name, address)
  @name = name
  @address = address
  super
  header
  text_content
end
 

Если вам нужно передать много переменных, возможно, будет проще добавить методы в свой класс ReportPdf для их получения:

 pdf = ReportPdf
  .new
  .name(@name)
  .address(@address)
  .salutation(@salutation)
  .something_else(@value)
  etc
 

Комментарии:

1. Я попробовал это предложение. Моя переменная экземпляра по-прежнему не отображается в pdf

2. Как только у вас появится переменная в объекте ReportPdf, вы добавите ее как любой существующий текст. Если это не работает, можете ли вы показать, что вы сделали и что произойдет, когда вы это сделаете?

3. .name(@name) не является идиоматически правильным Ruby, и это не очень хорошее предложение. В Ruby вы бы использовали сеттер pdf.name = @name , если бы действительно хотели установить данный атрибут. Еще лучше было бы использовать аргументы ключевых слов в вашем инициализаторе.

4. Существует также проблема, связанная с тем, что вы нарушаете сигнатуру инициализатора суперкласса, что приведет к нарушению заводских методов, которые полагаются на него.

5. Справедливые замечания, Макс — было бы лучше поступить по-своему, хотя принципы остаются в силе. Использование attr_writer на объекте дало бы несколько хороших чистых методов для передачи требуемых переменных. Я вижу, что вы дали более полный ответ ниже, который выглядит довольно хорошо.

Ответ №3:

Похоже, ты близок к этому. Вы хотите распечатать весь документ со страницы индекса или только тот, который представлен в форме, что было бы проще всего сделать со страницы показать. Вместо печати одного документа из индекса распечатайте его на странице показать

 def show
  @template = Template.find(params[:id])

  respond_to do |format|
    format.html
    format.pdf do
      pdf = ReportPdf.new(template: @template)
      send_data pdf.render, filename: 'report.pdf', type: 'application/pdf', 
      disposition: "inline"
    end
  end
end
 

Затем вы можете добавить параметры шаблона, которые вам нужны

 class ReportPdf < Prawn::Document
def initialize(template)
    @template = template
    super()
    header
    text_content
end

def header
    #This inserts an image in the pdf file and sets the size of the image
    image "#{Rails.root}/app/assets/images/logo.jpg", width: 230, height: 75
  end

  def text_content
    # The cursor for inserting content starts on the top left of the page. Here we move it down a little to create more space between the text and the image inserted above
    y_position = cursor - 50

    # The bounding_box takes the x and y coordinates for positioning its content and some options to style it
    bounding_box([0, y_position], :width => 270, :height => 300) do
      text "Name: #{@template.name}, Address: #{@template.address}, Ect...", size: 15, style: :bold
      text "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ."
    end

    bounding_box([300, y_position], :width => 270, :height => 300) do
      text "Duis vel", size: 15, style: :bold
      text "Duis vel tortor elementum, ultrices tortor vel, accumsan dui. Nullam in dolor rutrum, gravida turpis eu, vestibulum lectus. Pellentesque aliquet dignissim justo ut fringilla. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut venenatis massa non eros venenatis aliquet. Suspendisse potenti. Mauris sed tincidunt mauris, et vulputate risus. Aliquam eget nibh at erat dignissim aliquam non et risus. Fusce mattis neque id diam pulvinar, fermentum luctus enim porttitor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos."
    end
    
    end

  end
 

Затем в своем представлении шоу вы можете просто перейти по ссылке на него или нажать кнопку, чтобы перейти по ссылке на него

 <%= link_to 'Download PDF', template_path(@template, format:"pdf"), class: "btn btn-primary" %>
 

Комментарии:

1. Спасибо, что это работает ! Мне пришлось изменить эту строку : pdf = ReportPdf.new(шаблон: @шаблон) на pdf = ReportPdf.new(@шаблон)

Ответ №4:

Используйте переменную экземпляра в модели. например: @name = имя и т.д.

По умолчанию переменная экземпляра доступна во всем цикле запросов.

Комментарии:

1. Пожалуйста, добавьте дополнительные сведения, чтобы расширить свой ответ, например, ссылки на рабочий код или документацию.