Rails: How do I upload Paperclip image attachment to a DB from an unrelated controller + Strong params requirement

1k views Asked by At

Help Request

How do I upload image attachment to from an unrelated controller + Strong params requirements?

Background

I have one controller, Cars. I have two models Car and Garage.

Cars controller creates a Garage object based on a user's vehicle attributes (users are from devise). There is no Garages controller since the Cars controller create a new @garage object.

The Garage model is where attributes from the Car model and other values from the Cars controller are to be stored.

The Cars show page list all the values

Please know this application is working fine as it is except the part where I would like to have a user upload a photo (paperclip gem) of their vehicle to the garages db.

The way this application _supposed_functions is...

  1. cars/1 This show page contains a list of all vehicle's attributes and a button, Browse... and an Add to Garage button.
  2. Selecting the Browse... button allows you to attach a photo of your vehicle. This is made possible using the paperclip gem.
  3. Once your photo is attached, you can select the Add to Garage button.
  4. The Cars controller creates a Garage object with several vehicle attributes including some from devise methods, instance variables and places these values into the garages table.

There are NO errors returned. All of the values are entered into the garages db except for the attached image.

Below are the files


cars/cars_controller.rb

class CarsController < ApplicationController
  before_action :set_car

  def show
    @garage = Garage.find(params[:id])
  end

  def create    
    @garage = Garage.create( tech_id:  @car.service.tech.id, :customer_id: current_customer.id )
    if @garage.save
      redirect_to techs_path, notice:  "You car has been added to the garage!" 
    elsif 
      redirect_to tech_path, notice:  "Uh oh, flat tire!" 
    end
  end

  private

  def set_car
    @car = Car.find(params[:id])
  end

  def garage_params
    params.permit(:tech_id, :customer_id )
  end

end

MODELS

models/car.rb (unsure if the has_attached_file is needed in this model but added anyway)

class Car < ActiveRecord::Base
  belongs_to :service
  belongs_to :tech #added 5/27

  has_attached_file :garage_photo, styles: { medium: "300x300>", :thumb => "100x100>" }#, :default_url => "/images/:style/missing.png"
  validates_attachment_content_type :garage_photo, content_type: /\Aimage\/.*\Z/
end

models/garage.rb

class Garage < ActiveRecord::Base

  belongs_to :customer
  belongs_to :tech

  has_attached_file :garage_photo, styles: { medium: "300x300>", :thumb => "100x100>" }#, :default_url => "/images/:style/missing.png"
  validates_attachment_content_type :garage_photo, content_type: /\Aimage\/.*\Z/

end

VIEWS

cars/show.html.erb

<h2>Please review to add to garage </h2>
<b>Your garage tech:</b> <%= @car.service.tech.id %><br>
<b>ID:</b> <%= current_customer.id %><br>

<%= form_for @garage, :html => { :multipart => true } do |f| %>
  <%= f.file_field :garage_photo %>
<% end %>


<%= button_to 'Add to Garage', tech_cars_path(tech_id: @car.service.tech.id, id: @car.id) %>
<%= link_to 'Back to tech', tech_path(@car.service.tech.id) %>

Routes

Rails.application.routes.draw do
  devise_for :customers, controllers: { sessions: 'customers/sessions' }, :path => ''
  devise_for :techs, controllers: { sessions: 'techs/sessions' } 
  #, :path => ''#, :path_names => { :sign_in => "login", :sign_out => "logout" }

  resources :techs, only: [:index, :show], shallow: true do
    resources :cars, only: [:show, :create]
  end

  resources :service_menus, :services, :garages
    root to: "home#index"
end

6-12 Add more details

_add_attachment_garage_photo_to_garages.rb Migration file

class AddAttachmentGaragePhotoToGarages < ActiveRecord::Migration
  def change
    change_table :garages do |t|
      t.attachment :garage_photo
    end
  end
end

mysql> describe garages snippet

| garage_photo_updated_at   | datetime     | YES  |     | NULL    |                |
| garage_photo_file_size    | int(11)      | YES  |     | NULL    |                |
| garage_photo_content_type | varchar(255) | YES  |     | NULL    |                |
| garage_photo_file_name    | varchar(255) | YES  |     | NULL  

| |


Please advise on the issues below:

  1. How can I upload image attachment to garages db from an unrelated Cars controller? Everything gets added to the garages db except for the image attachment. Please keep in mind there are no errors returned when Add to Garage button is selected. Is this a strong params issue?

  2. Are strong params required in the Cars controller? If so, how do I assign the db :keys to instance @variables? I've searched all over but it's unclear how to assign instance variables to keys for strong params.

    @garage = Garage.create(garage_params)
    params.permit(:tech_id, :customer_id )

  3. If possible, please provide any refactoring approaches you may have.

Any help will be appreciated. Please let me know if you require more details.

Thanks

2

There are 2 answers

1
Prashant4224 On

You need to include garage_photo in strong parameter

cars/cars_controller.rb

class CarsController < ApplicationController
  before_action :set_car

  def show
    @garage = Garage.find(params[:id])
  end

  def create    
    @garage = Garage.create(garage_params)
    if @garage.save
      redirect_to techs_path, notice:  "You car has been added to the garage!" 
    elsif 
      redirect_to tech_path, notice:  "Uh oh, flat tire!" 
    end
  end

  private

  def set_car
    @car = Car.find(params[:id])
  end

  def garage_params
    params.permit(:tech_id, :customer_id, :garage_photo )
  end
end

cars/show.html.erb

<h2>Please review to add to garage </h2>
<b>Your garage tech:</b> <%= @car.service.tech.id %><br>
<b>ID:</b> <%= current_customer.id %><br>

<%= form_for @garage, :html => { :multipart => true } do |f| %>
  <%= f.hidden_field :tech_id, value: @car.service.tech.id %>
  <%= f.hidden_field :customer_id, value: current_customer.id %>
  <%= f.file_field :garage_photo %>
<% end %>

<%= button_to 'Add to Garage', tech_cars_path(tech_id: @car.service.tech.id, id: @car.id) %>
<%= link_to 'Back to tech', tech_path(@car.service.tech.id) %>
5
Patrick Mulligan On

I'm hitting myself for not seeing it sooner. Your view has no submit button for the same form that has the file upload field! <%= button_to %> creates a completely separate form, basically encapsulates the entire form into a single button. Therefore any value you provided in the form above will not be submitted when clicking this button. Instead you should create a standard <%= f.submit "Submit" %> type button.