Storing Carrierwave as json into an existing jsonb column - ruby-on-rails

I'm not sure if this is even possible using Carrierwave, I'm still learning my way around Ruby and Rails so bear with me.
I have a simple form to record observations. Each observation has data that can be recorded against it and I store this in a JSONB column within the observation (I will eventually store multiple sets of data against an observation). I want to be able to upload an image through Carrierwave and store it with the data within the JSONB column rather than saving it to its own column. So my saved data for this column would be like this for example...
{
"ph":"",
"ecoli":"",
"nitri":"Less than 0.5",
"oxygen":"",
"clarity":"bottom visible",
"nitrates":"Less than 0.5",
"conditions":[
"Wildlife Death",
"Shoreline Alterations",
"Water Quality"
],
"observed_on":"2015-06-21T04:45",
"invasive_species":[
"Phragmites",
"Loosestrife",
"Dog-Strangling Vine"
],
"phosphates_threshold":"less than 0.2",
"image":[
"url": "the/url",
"thumbnail: "the/thumbnail/url",
"medium":"the/thumbnail/url"
.....
]
}
Some of the supporting code for reference...
observation.rb
class Observation < ActiveRecord::Base
belongs_to :user
has_many :comments
serialize :observation_data, HashSerializer
store_accessor :observation_data
end
observation_data.rb - tableless model
class ObservationData < ActiveRecord::Base
belongs_to :observation
mount_uploader :image, ImageUploader
end
_form.html.erb
<%= form_for #observation do |f| -%>
...Other form items
<fieldset>
<legend>Observation data</legend>
<%= render "observation_data", :f => f %>
</fieldset>
<div class="actions">
<%= f.submit "Submit", class: "button" %>
</div>
<% end %>
_observation_data.html.erb
<%= f.fields_for :observation_data, OpenStruct.new(#observation.observation_data) do |o| %>
...Other form items
<div class="field">
<%= o.label :image, "Upload an image" %>
<%= o.file_field :image %>
</div>
...Other form items
<% end %>
observations_controller.rb
class ObservationsController < ApplicationController
before_action :set_observation, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
#observations = Observation.all
#user = current_user.id
end
def show
#observations = Observation.find_by(id: params[:id])
#observation_data = #observation.observation_data
#comments = #observation.comments.all
#comment = #observation.comments.build
#user = User.find_by(id: #observation.user_id)
end
def new
#observation = Observation.new
end
def edit
end
def create
#observation = Observation.new(observation_params)
#observation.user_id = current_user.id
respond_to do |format|
if #observation.save
format.html { redirect_to #observation, notice: 'Observation was successfully created.' }
format.json { render action: 'show', status: :created, location: #idea }
else
format.html { render action: 'new' }
format.json { render json: #observation.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #observation.update(observation_params)
format.html { redirect_to #observation, notice: 'Observation was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #observation.errors, status: :unprocessable_entity }
end
end
end
def destroy
#observation.destroy
respond_to do |format|
format.html { redirect_to root_url }
format.json { head :no_content }
end
end
private
def set_observation
#observation = Observation.find(params[:id])
end
def observation_params
params.require(:observation).permit(:user_id, :lat, :lng, :name, :description, :comment, observation_data: [:observed_on, :image, :ph, :oxygen, :ecoli, :phosphates_threshold, :clarity, :nitri, :nitrates, wildlife: [], conditions: [], invasive_species: []])
end
end
The problem for me is mount_uploader :image, ImageUploader is always looking for an :image column, how can I merge the Carrierwave response this with JSON in another column? Is it even possible?

Related

rails strong parameters not work correctly

i have a rails app. i have strange problem in saving form
this is my ticket model .
class Ticket < ApplicationRecord
belongs_to :user
has_many :ticketissues , inverse_of: :ticket
accepts_nested_attributes_for :ticketissues, :reject_if => lambda { |a| a[:body].blank? }
end
this is ticketisue model
class Ticketissue < ApplicationRecord
belongs_to :user
belongs_to :ticket
validates :body, presence: true
end
this is ticket controller
class TicketsController < ApplicationController
before_action :set_ticket, only: [:show, :edit, :update, :destroy]
# GET /tickets
# GET /tickets.json
def index
#tickets = Ticket.all
end
# GET /tickets/1
# GET /tickets/1.json
def show
end
# GET /tickets/new
def new
#ticket = Ticket.new
end
# GET /tickets/1/edit
def edit
end
# POST /tickets
# POST /tickets.json
def create
#ticket = Ticket.new(ticket_params)
#ticket.user_id = current_user.id
#ticket.ticketissues.build
respond_to do |format|
if #ticket.save
format.html { redirect_to #ticket, notice: 'Ticket was successfully created.' }
format.json { render :show, status: :created, location: #ticket }
else
format.html { render :new }
format.json { render json: #ticket.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /tickets/1
# PATCH/PUT /tickets/1.json
def update
respond_to do |format|
if #ticket.update(ticket_params)
format.html { redirect_to #ticket, notice: 'Ticket was successfully updated.' }
format.json { render :show, status: :ok, location: #ticket }
else
format.html { render :edit }
format.json { render json: #ticket.errors, status: :unprocessable_entity }
end
end
end
# DELETE /tickets/1
# DELETE /tickets/1.json
def destroy
#ticket.destroy
respond_to do |format|
format.html { redirect_to tickets_url, notice: 'Ticket was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ticket
#ticket = Ticket.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def ticket_params
params.require(:ticket).permit(:subject, :subsubject, :user_id, ticketissues_attributes: [
:body, :id, :_destroy] )
#params.require(:ticket).permit!
end
end
and my view is like this
<%= f.input :subject , collection: [ "تغییر اطلاعات کسب و کار",
"تغییر اطلاعات یک کوپن",
"سایر موارد"] %>
<%= f.input :subsubject %>
<!-- <%= f.association :user %> -->
</div>
<%= f.simple_fields_for :ticketissue do |p| %>
<%= p.input :body %>
<% end %>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
but when i want to create a ticket , form will not save to database
and i get this error:
Started POST "/tickets" for 127.0.0.1 at 2017-04-11 23:52:33 +0430
Processing by TicketsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"fsl6nTe0PjmBKpeuh16BRFlYOw0MB93LEYDVEAl6TtT/uu/LwGTA0P2q0bRxIxBUqHqZINXHntrZLt7MuCG84Q==", "ticket"=>{"subject"=>"تغییر اطلاعات کسب و کار", "subsubject"=>"lk", "ticketissue"=>{"body"=>"lkjkjkjkjkkjkj"}}, "commit"=>"Create Ticket"}
Unpermitted parameter: ticketissue
but when i use console and this command:
Ticket.create(subject: 'test' , subsubject: 'ticket test' , ticketissues_attributes: [{body: "[some thing" }] )
every things work fines and all data save.
tanks for read and help.
You must use the plural here
= f.simple_fields_for :ticketissues do |p|

collection_select is not creating the association table

I'm currently trying to add a collection_select of ranches to my staff
And I saw that it's better to create an extra table to make this association.
And I follow some tutorial, but is not working on my side
This is my code :
Staffs/_form :
<%= form_for(#staff) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= fields_for(#staff_ranch) do |x| %>
<div class="field">
<%= x.collection_select(:ranch_id, #all_ranch, :id, :name, { }, {:multiple => true}) %>
</div>
<%end%>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
My models :
- Ranch :
has_many :ranchstaffs
has_many :staffs, :through => :ranchstaffs
- Staff :
has_many :ranchstaffs
has_many :ranches, :through => :ranchstaffs
-Ranchstaff :
belongs_to :ranch
belongs_to :staff
Staff controller :
class StaffsController < ApplicationController
before_action :set_staff, only: [:show, :edit, :update, :destroy]
# GET /ranches
# GET /ranches.json
def index
#staffs = current_user.staffs
end
# GET /ranches/1
# GET /ranches/1.json
def show
end
# GET /ranches/new
def new
#staff = Staff.new
#all_ranch = current_user.ranches
#staff_ranch = #staff.ranchstaffs.build
end
# GET /ranches/1/edit
def edit
end
# POST /ranches
# POST /ranches.json
def create
#staff = Staff.new(staff_params)
#staff.update(user_id: current_user.id)
respond_to do |format|
if #staff.save
format.html { redirect_to #staff, notice: 'Staff was successfully created.' }
format.json { render :show, status: :created, location: #staff }
else
format.html { render :new }
format.json { render json: #staff.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /ranches/1
# PATCH/PUT /ranches/1.json
def update
respond_to do |format|
if #staff.update(staff_params)
format.html { redirect_to #staff, notice: 'Staff was successfully updated.' }
format.json { render :show, status: :ok, location: #staff }
else
format.html { render :edit }
format.json { render json: #staff.errors, status: :unprocessable_entity }
end
end
end
# DELETE /ranches/1
# DELETE /ranches/1.json
def destroy
#staff.destroy
respond_to do |format|
format.html { redirect_to staffs_url, notice: 'Ranch was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_staff
#staff = Staff.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def staff_params
params.require(:staff).permit(:name, :user_id, :cat, :ranch_id)
end
end
Can you explain me why the model ranchstaff was not created after a creation of a new staff ?
As you are using fields_for you are using nested form but you are not permitting the parameters properly. First make change in your form:
<%= f.fields_for(#staff_ranch) do |x| %>
<div class="field">
<%= x.collection_select(:ranch_id, #all_ranch, :id, :name, { }, {:multiple => true}) %>
</div>
<% end %>
And then in your controller:
def staff_params
params.require(:staff).permit(:name, :user_id, :cat, ranchstaff_attributes: [ranch_id: []])
end
And in your Staff model write:
accepts_nested_attributes_for :ranchstaffs
Then your ranchstaff should be created when the User is being created.
Your ranch_id is coming in an array. So u have to specify that ranch_id would be array in strong parameters.
so your staff_params method would look like this
def staff_params
params.require(:staff).permit(:name, :user_id, :cat, :staff_ranch_attributes =>[:ranch_id => []])
end

Why no error with unassigned variable?

I have a pupils model and a groups model. When adding a new pupil I have a collection_select box with :multiple=> true so that the pupil can be put into several groups.
<div class="field">
<%= f.label "All Groups" %><br />
<%= collection_select(:groups, :id, #all_groups,
:id, :name, {},
{:multiple => true}) %>
</div>
I have an edit pupil form that when loaded selects the groups the pupil was previously assigned so that they can be changed if needs be so has the extra bit in {} in the collection select options;
<div class="field">
<%= f.label "All Groups" %><br />
<%= collection_select(:groups, :id, #all_groups,
:id, :name, {selected: #previous_selection},
{:multiple => true}) %>
</div>
the #previous_selection is set in the pupils_controller;
#previous_selection = Array.new
#pupil.groups.each do |pg|
#previous_selection.push(pg.id)
end
This is in the def edit block so only setup for the edit page.
Here is the PupilsController;
class PupilsController < ApplicationController
before_action :set_pupil, only: [:show, :edit, :update, :destroy]
def index
#pupils = Pupil.all
end
def show
#pupil_groups = #pupil.groups
end
def new
#pupil = Pupil.new
#all_groups = set_pupil_list
end
def edit
#all_groups = set_pupil_list
#previous_selection = Array.new
#pupil.groups.each do |pg|
#previous_selection.push(pg.id)
end
end
def create
#pupil = Pupil.new(pupil_params)
clean_select_multiple_params
logger.debug "The groups parameter contains: #{params[:groups][:id]}"
selected_groups = Group.find(params[:groups][:id])
#pupil.groups = selected_groups
respond_to do |format|
if #pupil.save
format.html { redirect_to #pupil, notice: 'Pupil was successfully created.' }
format.json { render action: 'show', status: :created, location: #pupil }
else
format.html { render action: 'new' }
format.json { render json: #pupil.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #pupil.update(pupil_params)
clean_select_multiple_params
selected_groups = Group.find(params[:groups][:id])
#pupil.groups = selected_groups
format.html { redirect_to #pupil, notice: 'Pupil was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #pupil.errors, status: :unprocessable_entity }
end
end
end
def destroy
#pupil.destroy
respond_to do |format|
format.html { redirect_to pupils_url }
format.json { head :no_content }
end
end
def full_name
#fn = #pupil.given_name
#sn = #pupil.surname
#full_name = #fn + #sn
end
private
def set_pupil
#pupil = Pupil.find(params[:id])
end
def set_pupil_list
Group.all
end
def clean_select_multiple_params hash = params
hash.each do |k, v|
case v
when Array then v.reject!(&:blank?)
when Hash then clean_select_multiple_params(v)
end
end
end
def pupil_params
params.require(:pupil).permit(:given_name, :surname, :date_of_birth, :gender, :ethnicity)
end
end
When the new pupil page is requested the _form.html.erb file is used that has the {selected: #previous_selection} argument in it that has not been set up by def new in the pupils_controller but there is not a error message about #previous_selection not being initialized.
I would expect an error but am not getting one but do not understand why. Could someone please explain? I am new to programming in general so sorry if I am using the wrong terminolog.
Thank you
Leon
#previous_selection variable is nil, and hence in the view none of collection items will be selected. It is not necessary to initialize a variable to nil, rails does that.

Mysql2::Error: Data too long for column 'description' at row 1

I am using text-editor(wysihtml5).I am having problem in saving data in database.If I have typed more than 20 lines. it shows error like " Mysql2::Error: Data too long for column 'description' at row 1".and I am using rails4.
In Model
class News < ActiveRecord::Base
attr_accessible :name,:published_on,:description
#associations
validates :name, presence: true
validates :published_on, presence: true
validates :description, presence: true
end
In Controller
class NewsController < ApplicationController
layout :setting_layout
before_action :set_news, only: [:show, :edit, :update, :destroy]
# GET /news
# GET /news.json
def index
#news = News.all
end
# GET /news/1
# GET /news/1.json
def show
end
# GET /news/new
def new
#news = News.new
end
# GET /news/1/edit
def edit
end
# POST /news
# POST /news.json
def create
#news = News.new(news_params)
respond_to do |format|
if #news.save
format.html { redirect_to #news, notice: 'News was successfully created.' }
format.json { render action: 'show', status: :created, location: #news }
else
format.html { render action: 'new' }
format.json { render json: #news.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /news/1
# PATCH/PUT /news/1.json
def update
respond_to do |format|
if #news.update(news_params)
format.html { redirect_to #news, notice: 'News was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #news.errors, status: :unprocessable_entity }
end
end
end
# DELETE /news/1
# DELETE /news/1.json
def destroy
#news.destroy
respond_to do |format|
format.html { redirect_to news_index_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_news
#news = News.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def news_params
params.require(:news).permit(:name, :published_on, :description)
end
end
In View
<%= simple_form_for #news, html: {class: 'form-inline form-horizontal'}, :validate => true do |f|%>
<p><font color="red">Fields with * are required.</font></p>
<div class="inputs">
<%= f.input :name %>
<%= f.input :published_on, as: 'string', input_html: {class: 'datepicker'} %>
<%= f.input :description, as: 'text', :input_html =>{:rows => '100', :cols => '100', :class => 'input wysihtml5' }%>
</div>
<div class="form-actions">
<%= button_tag(type: 'submit', class: "btn btn-primary") do %>
<i class="icon-ok icon-white"></i> Save
<% end %>
</div>
<% end %>
In Js file
$(document).ready(function(){
$(".wysihtml5").wysihtml5();
})
In view I have given row and cols value. But it takes only cols value.
You have probably set it as a string in your migration file, rather than text.
string fields are interpreted as varchar, and are limited in character length. text fields are not.
if the field is text, change it to longtext e.g.
change_column :your_table, :your_column, :longtext

Show list of attachments using Paperclip in Rails Application

I am having issues with paperclip in my rails application. I am able to attach multiple files (PDFs) to my form, but when I try to show more than 1 attachment in the show.html.erb file I get errors.
The code that works in the edit and new views:
<%= f.fields_for :assets do |asset| %>
<% if asset.object.new_record? %>
<%= asset.file_field :document %>
<% end %>
<% end %>
</div>
<div class="existingPaperclipFiles">
<% f.fields_for :assets do |asset| %>
<% unless asset.object.new_record? %>
<div class="thumbnail">
<%= link_to( image_tag(asset.object.document.url(:thumb)), asset.object.document.url(:original) ) %>
<%= asset.check_box :_destroy %>
</div>
<% end %>
<% end %>
</div>
I have created a separate assets model to keep all the attachments related to my equipment model. When I create a "link_to asset.object.document.url" in the show view I get NoMethod errors. I want to attach both .doc, PDF, and image files to my application if there is a better way than paperclip please help!
The assets model:
class Asset < ActiveRecord::Base
belongs_to :equipment
has_attached_file :document, :styles => {:thumb => '150x150#', :medium => '300x300#', :large => '600x600#' }
end
The equipment model:
class Equipment < ActiveRecord::Base
validates :equipment_id, presence: true
validates :location, presence: true
has_many :assets, :dependent => :destroy
accepts_nested_attributes_for :assets, :allow_destroy => true
end
My equipment_controller:
class EquipmentController < ApplicationController
def index
#equipment = Equipment.paginate(page: params[:page])
end
def show
#equipment = Equipment.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #equipment }
end
end
def new
#equipment = Equipment.new
5.times {#equipment.assets.build}
end
def create
#equipment = Equipment.new(params[:equipment])
respond_to do |format|
if #equipment.save
format.html { redirect_to #equipment, notice: 'Equipment was successfully added.' }
format.json { render json: #equipment, status: :created, location: #equipment }
else
format.html { render action: "new" }
format.json { render json: #equipment.errors, status: :unprocessable_entity }
end
end
end
def edit
#equipment = Equipment.find(params[:id])
5.times {#equipment.assets.build}
end
def update
#equipment = Equipment.find(params[:id])
respond_to do |format|
if #equipment.update_attributes(params[:equipment])
format.html { redirect_to #equipment, notice: 'Equipment was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #equipment.errors, status: :unprocessable_entity }
end
end
end
def destroy
#equipment = Equipment.find(params[:id])
#equipment.destroy
respond_to do |format|
format.html { redirect_to equipment_url }
format.json { head :no_content }
end
end
private
def correct_user
#Equipment = Equipment.find(params[:id])
redirect_to(root_path) unless current_user?(#Equipment)
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
Any help is greatly appreciated.
You didn't give the code for the show view where you're having the error, but you should be able to do something like this to show thumbnails with links to the original files:
<% #equipment.assets.each do |asset| %>
<%= link_to image_tag(asset.document.url(:thumb)), asset.document.url(:original) %>
<% end %>
I'm not sure why you have "object" in your Paperclip URLs, as I haven't seen that format used for Paperclip.
I actually was able to figure this out by doing the following:
<% for asset in #equipment.assets %>
<p>
<%= link_to asset.document_file_name,
asset.document.url(:original) %>
</p>
<% end %>

Resources