Ruby on Rails - Image Upload - ruby-on-rails

I'd like to add images to a model. I have Users set up with Devise and they have_many Items that they are selling.
I would now like to add an array of images to the Item model (not sure if this is the best approach).
I have looked a Paperclip but can only do one image. Also looked at carrier wave but not sure how to implement on existing model.
Here is some of my code.
Item.rb
class Item < ActiveRecord::Base
belongs_to :user
validates :title, presence: true
validates :price, presence: true
validates :description, presence: true
end
items_controller.rb
class ItemsController < ApplicationController
before_action :findItem, only: [:edit, :update, :sold]
def index
#items = Item.all
end
def new
#item = Item.new
end
def create
#item = Item.create(item_params)
#item.user = current_user
if #item.save
flash[:success] = "Your item was successfully listed."
render 'show'
else
flash[:error] = "Your item could not be listed. Please try again."
render 'new'
end
end
def show
#item = Item.find(params[:id])
end
def edit
end
def update
if #item.update(item_params)
flash[:success] = "Your item listing was updated successfully."
redirect_to item_path(#item)
else
flash[:error] = "Your listing was not updated. Please try again."
render 'edit'
end
end
def sold
#item.toggle(:sold)
#item.save
redirect_to item_path(#item)
end
private
def item_params
params.require(:item).permit(:title, :price, :description)
end
def findItem
#item = Item.find(params[:id])
end
end
Form for Item/new.html.erb
<div class="row">
<div class="col-xs-12">
<%= form_for(#item, :html => {class: "form-horizontal", role: "form"}) do |f| %>
<div class="form-group">
<div class="control-label col-sm-2">
<%= f.label :title %>
</div>
<div class="col-sm-8">
<%= f.text_field :title, class: "form-control", placeholder: "What are you selling?", autofocus: true %>
</div>
</div>
<div class="form-group">
<div class="control-label col-sm-2">
<%= f.label :price %>
</div>
<div class="col-sm-8">
<%= f.number_field :price, class: "form-control" %>
</div>
</div>
<div class="form-group">
<div class="control-label col-sm-2">
<%= f.label :description %>
</div>
<div class="col-sm-8">
<%= f.text_area :description, rows: 10, class: "form-control", placeholder: "Describe your item. The more detail you include, the more likely it is to sell." %>
</div>
</div>
<div class="form-group">
<div class="center col-sm-offset-1 col-sm-10">
<%= f.submit class: "btn btn-primary btn-lg" %>
</div>
</div>
<% end %>
<div class="center col-xs-4 col-xs-offset-4">
<%= link_to "[ Cancel and return to listing page ]", items_path %>
</div>

You simply want to create an Image model. And set the relation with Item as follows: Item has_many :images, and Image belongs_to :item.
But, yeah, paperclip is a good start.
EDIT: Oh, and welcome Rails, you will find a good community ready to help. You might also find useful to search for accepts_nested_attributes_for so you can have the images uploaded in your Item form and cocoon to dynamically add and remove images on the item's form.

#app/models/item.rb
class Item < ActiveRecord::Base
has_many :images
accepts_nested_attributes_for :images
validates :title, :price, :description, presence: true
end
#app/models/image.rb
class Image < ActiveRecord::Base
belongs_to :item
has_attached_file :picture
end
--
The above will allow you to create an Item, which will have any number of images that you want. You can pass the new images through accepts_nested_attributes_for:
#app/controllers/items_controller.rb
class ItemsController < ApplicationController
def new
#item = Item.new
#item.images.build
end
def create
#item = Item.new item_params
#item.save
end
private
def item_params
params.require(:item).permit(images_attributes: [:picture])
end
end
#app/views/items/new.html.erb
<%= form_for #item do |f| %>
<%= f.fields_for :images do |i| %>
<%= i.file_field :picture %>
<% end %>
<%= f.submit %>
<% end %>

Related

param is missing or the value is empty: post in Postscontroller#new

I am trying to create a Website with Posts and stuff.
Currently I have a Post Model with its components.
Whenever I try to open posts/new this error message appears
ActionController::ParameterMissing in PostsController#new
param is missing or the value is empty: post
post_controller
def new
#post = current_user.posts.build(post_params)
if #post.save!
redirect_to #post
else
def post_params
params.require(:post).permit(:title, :body)
end
I was able to create posts on localhost:3000/post/new before. I just wanted to try again and realized I must've messed something up.
This is my Post form.
<div class="form-control">
<div class="card-my-4">
<%= form_for Post.new do |f| %>
<div class="card-body">
<strong>post title: </strong>
<%= f.text_area :title, :maxlength => 40, class: 'form-control', rows: 1, id: 'textareaedit' %>
</div>
<div class="card-body">
<strong>Compose your Quote content: </strong>
<div class="form-group">
<%= f.text_area :body, :maxlength => 240, class: 'form-control', rows: 3 %>
</div>
<hr>
<%= submit_tag "Submit", class: "btn btn-outline-success" %>
<% end %>
</div>
</div>
</div>
post.rb
class Post < ApplicationRecord
belongs_to :user
has_many :comments, dependent: :destroy
validates :title, presence: true, length: { minimum: 5 }
validates :body, presence: true, length: { minimum: 240 }
end
try change your code:
post_controller:
def create
#post = current_user.posts.build(post_params)
if #post.save!
redirect_to #post
else
....
end
def new
#post = Post.new
end
views:
<div class="form-control">
<div class="card-my-4">
<%= form_for #post do |f| %>
............

has_many join form with collection checkboxes not saving more than one checkbox value

I am working on a form for a editorial calendar app. I have two things going out that are pretty similar and not working.
Working with 3 models: Platforms, Posts and Calendars. They are join tables. Platform <=> Post, Post <=> Calendars
Post/new & Post/edit form:
<div class="container">
<div class="form-field">
<%= form_for #post do |f| %>
<%= f.label :title %>
<%= f.text_field :title, required: true %> <br>
Title is required.
</div>
<div class="form-field">
<%= f.label :content%>
<%= f.text_area :content%>
</div>
<div class="form-field">
<%= f.label :link %>
<%= f.text_field :link %>
</div>
<div class="file-field">
<%= f.label :picture%>
<%= f.file_field :picture, id: :post_picture%>
</div>
<div class="file-field">
<%= f.label :finalized %>
<%= f.radio_button :finalized , true%>
<%= f.label :finalized, "Yes" %>
<%= f.radio_button :finalized, false %>
<%= f.label :finalized, "No" %>
</div>
<%= f.hidden_field :user_id %> <br>
<div class="form-field">
<%= f.fields_for :platform_attributes do |platform| %>
<%= platform.label :platform, "Social Platforms"%>
<%= platform.collection_check_boxes :platform_ids, Platform.all, :id, :name %> <br> <br>
</div>
<div>
<h4> Or Create a new platform: </h4>
<%= platform.label :platform, 'New Platform'%>
<%= platform.text_field :name%> <br> <br>
</div>
<% end %>
<%= f.submit%>
<% end %>
</div>
My post controller is handling the checkboxes issue, and the "schedule post" issue. It will only allow me to schedule for one calendar, and it does not save the updates and add additional calendars.
Posts Controller:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :schedule_post, :destroy]
def new
#posts = current_user.posts.select {|p| p.persisted?}
#post = current_user.posts.build
#platforms = Platform.all
end
def edit
#calendars = current_user.calendars
#platforms = Platform.all
end
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to post_path(#post)
else
redirect_to new_post_path
end
end
def update
#post.update(post_params)
if #post.save
redirect_to post_path(#post), notice: 'Your post has been updated.'
else
redirect_to edit_post_path(#post)
end
end
def schedule_post
#calendar_post = CalendarPost.new(calendar_post_params)
if #calendar_post.save
binding.pry
redirect_to post_path(#post)
else
render 'show'
end
end
private
def set_post
#post = Post.find(params[:id])
end
def set_calendars
#calendars = current_user.calendars
end
def post_params
params.require(:post).permit(:title, :content, :link, :finalized, :picture, :user_id, :platform_attributes => [:platform_ids, :name])
end
def calendar_post_params
params.require(:calendar_post).permit(:post_id, :calendar_id, :date, :time)
end
end
I want the user to be able to add a post to multiple platforms and multiple calendars because of the versatility of what someone may need.
I also have my setter in my Post model.
class Post < ApplicationRecord
has_many :calendar_posts
has_many :calendars, through: :calendar_posts
has_many :platform_posts
has_many :platforms, through: :platform_posts
belongs_to :user
def platform_attributes=(platform_attributes)
if platform_attributes['platform_ids']
platform_attributes.platform_ids.each do |id|
platform = Platform.find(id: id)
self.platforms << platform
end
end
if platform_attributes['name'] != ""
platform = Platform.find_or_create_by(name: platform_attributes['name'])
self.platforms << platform
end
end
thoughts? why are they not saving to more than one calendar or more than one platform if they choose to have more than one?
Here is the updated code... and more of what I know about these changes and what is happening.
My submit button is not working for some odd reason on my form, so I'm trying to get the params submitted but it won't even route to give me params even if I raise them, nothing is happening.
On the form you can choose checkboxes or add in a platform. If you add in a platform it creates that one but it does not also save the other ones you selected. If you go to edit the post, and click submit with changes, no page loads at all and nothing is happening in log. It's just idle.
<%= f.fields_for :platform_attributes do |platform| %>
assumes you are creating one platform... it says "these are the fields for this platform"
but platform_ids is intended to be a selection of a set of platforms... and probably should be outside of the fields_for section (which should only surround the name field).
try something like the following:
<div class="form-field">
<%= f.label :platform_ids, "Social Platforms"%>
<%= f.collection_check_boxes :platform_ids, Platform.all, :id, :name %> <br> <br>
</div>
<div>
<%= f.fields_for :platform_attributes do |platform| %>
<h4> Or Create a new platform: </h4>
<%= platform.label :name, 'New Platform'%>
<%= platform.text_field :name%> <br> <br>
<% end %>
<%# end fields_for %>
</div>
Also you'll need to update permit/require appropriately eg
def post_params
params.require(:post).permit(:title, :content, :link, :finalized, :picture, :user_id, :platform_ids, :platform_attributes => [:name])
end
Note: not tested - bugs are left as an exercise for the reader ;)

using cocoon and checkboxes , I don't know how to recognize checked: true or false in edit

I am new to develop rails project, I have a nested form for submitting Event and Ticket by using gem 'cocoon'.And the form have some check_boxes .
When you submit new , it does not matter, but in edit, you can not put checked in my checkboxes.
How do i do that given my code below?
My error
undefined method `include?' for nil:NilClass
<%= f.check_box :payment_type, { multiple: true ,checked:f.object.payment_type.include?(pay), include_hidden: false }, pay %>
<%= f.label :payment_type, pay, :value => i %>
My Model
class Event < ActiveRecord::Base
has_many :tickets, inverse_of: :event
accepts_nested_attributes_for :tickets, allow_destroy: true
class Ticket < ActiveRecord::Base
belongs_to :event
My Controller
class EventsController < ApplicationController
before_action :set_event, only: [:show, :edit, :update, :destroy]
def new
#event = Event.new
end
def create
#event = Event.new(event_params)
if #event.save
flash[:notice] = 'wow'
redirect_to #event
else
flash[:notice] = 'oh..'
render 'new'
end
end
def edit
end
def update
if #event.update(event_params)
redirect_to #event
else
render 'edit'
end
end
My form
<div class="nested-fields">
<h3>tickets</h3>
<div class="row formsection text-center">
<div class="col-md-3">
<span class="label-title">fee</span>
</div>
<div class="col-md-9">
<div class='input-group'>
<%= f.text_field :fee, :placeholder => "fee" , :class => "form-control" %>
</div>
</div>
</div>
<div class="row formsection text-center">
<div class="col-md-3">
<span class="label-title">payment</span>
</div>
<div class="col-md-9">
<%= f.hidden_field :id %>
<% payments = { 'paypal' => 1, 'credit card' => 2 } %>
<% payments.each do |pay,i| %>
<%= f.check_box :payment_type, { multiple: true ,checked: f.object.payment_type.include?(i), include_hidden: false }, i %>
<%= f.label :payment_type, pay, :value => i %>
<br>
<% end %>
</div>
</div>
<%= link_to_remove_association 'remove this', f %>
</div>
Not sure why it works on new, but if payment_type is not yet set, and so is nil, this will give the error you showed.
So instead write something like:
<%- checked_value = f.object.payment_type.present? && f.object.payment_type.include?(i) %>
<%= f.check_box :payment_type, { multiple: true ,checked: checked_value, include_hidden: false }, i %>

How do I create recurring events with simple form and Ruby? Is ice-cube the best gem for this?

I'm building an events app using Rails and I need to figure out how Users can create Events which will be recurring - daily, weekly, monthly, yearly if they so wish.
It's not completely clear how to do this from my research but most roads seem to point toward using the ice_cube gem along with another - either schedulable or recurring_select for the form.
Is this the best way forward? If so, which is the best route and, if not, what is the best alternative?
Initially I want the form to offer an either/or option of 'recurring' or 'one-day' event. I'm using simple_form for all of my forms.
Here's the Event MVC position at the moment.
Event.rb -
class Event < ActiveRecord::Base
# You can call the scope whatever.
# the focus below is on the :date attribute from the events table - see also controller for index method/action
scope :not_yet_happened, -> { where('date >= ?', Date.current) }
belongs_to :category
belongs_to :user
has_many :bookings
has_many :comments
has_attached_file :image, styles: { medium: "300x300>" }
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
validates :title, :description, :location, :date, :time, :number_of_spaces, :price_pennies, :category_id, presence: true
validates :title, length: { minimum: 4 }
validates :description, length: { maximum: 250, too_long: "%{count} characters is the maximum allowed" }
monetize :price_pennies
# required for money-rails gem to function
end
events_controller.rb -
class EventsController < ApplicationController
before_action :find_event, only: [:show, :edit, :update, :destroy,]
# the before_actions will take care of finding the correct event for us
# this ties in with the private method below
before_action :authenticate_user!, except: [:index, :show]
# this ensures only users who are signed in can alter an event
def index
if params[:category].blank?
#events = Event.not_yet_happened.order("created_at DESC")
else
#category_id = Category.find_by(name: params[:category]).id
#events = Event.not_yet_happened.where(category_id: #category_id).order("created_at DESC")
end
# The above code = If there's no category found then all the events are listed
# If there is then it will show the EVENTS under each category only
end
def show
end
def new
#event = current_user.events.build
# this now builds out from a user once devise gem is added
# after initially having an argument of Event.new
# this assigns events to users
end
# both update and create actions below use event_params as their argument with an if/else statement
def create
#event = current_user.events.build(event_params)
# as above this now assigns events to users
# rather than Event.new
if #event.save
redirect_to #event, notice: "Congratulations, you have successfully created a new event."
else
render 'new'
end
end
def edit
# edit form
# #edit = Edit.find(params[:id])
#event = current_user.events.find(params[:id])
end
def update
if #event.update(event_params)
redirect_to #event, notice: "Event was successfully updated!"
else
render 'edit'
end
end
def destroy
#event.destroy
redirect_to root_path
end
private
def event_params
params.require(:event).permit(:title, :location, :date, :time, :description, :number_of_spaces, :is_free, :price, :organised_by, :url, :image, :category_id)
# category_id added at the end to ensure this is assigned to each new event created
end
def find_event
#event = Event.find(params[:id])
end
end
_form.html.erb (events) -
<%= simple_form_for(#event, html: { :class => "form-inline" }) do |f| %>
<% if #event.errors.any? %>
<h2><%= pluralize(#event.errors.count, "error") %> prevented this Event from saving:</h2>
<ul>
<% #event.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
<div class="form-group">
<%= f.collection_select :category_id, Category.all, :id, :name, {prompt: "Choose a category"} %>
<!-- The above code loop assigns a category_id to each event -->
</div>
<div class="form-group">
<%= f.input :image, as: :file, label: 'Image', class: "form-control" %>
</div>
<div class="form-group">
<%= f.input :title, label: false, placeholder: 'Title', class: "form-control" %>
</div>
<div class="form-group">
<%= f.text_field :location, id: 'geocomplete', class: "form-control" %>
</div>
<div class="form-group">
<%= f.text_field :date, placeholder: 'Date', id: 'datepicker', class: "form-control" %>
</div>
<div class="form-group">
<%= f.input :time, label: 'What time does the event start?', class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.input_field :description, label: false, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :number_of_spaces %>
<%= f.text_field :number_of_spaces, label: 'Number of spaces', class: "form-control" %>
</div>
<div class="form-group">
<%= f.input :is_free, label: 'Tick box if Event is free of charge', class: "form-control" %>
<!--f.input :currency, :collection => [['£GBP - British Pounds',1],['$USD - US Dollars',2],['€EUR - Euros',3]] -->
</div>
<div class="form-group">
<%= f.label :cost_per_person %>
<%= f.input :price, label: '(leave blank if free of charge)', class: "form-control" %>
</div>
<div class="form-group">
<%= f.input :organised_by, class: "form-control" %>
</div>
<div class="form-group">
<%= f.input :url, label: "My Website", class: "form-control" %>
</div>
<div class="form-group">
<%= f.button :submit, label: 'Submit', class: "btn btn-primary" %>
<% end %>
</div>
Mike. The fastest way is to use ice_cube + schedulable gems combo. Go through the Readme and you will be set up in minutes. It also features past_event_occurrences and future_event_occurrences.

Ruby on Rails - Display field from related table

I'm learning RoR and I'm having trouble getting a value from a related table to display. I've tried the suggestions mentioned here and here but I still haven't gotten it to work.
I have a customer record that has a one-to-many relationship with contacts.
Here are snips of my models:
class Contact < ActiveRecord::Base
belongs_to :customer
class Customer < ActiveRecord::Base
has_many :contacts, dependent: :destroy
and this is my Contacts index.html.erb that is producing the error
<% #contacts.each do |contact| %>
<tr class="<%= cycle("even pointer", "odd pointer") %>">
<td><%= contact.first_name %> <%= contact.last_name %></td>
<td><%= contact.customer.name %></td> <!-- this is the error line -->
<td><%= contact.office_phone %></td>
<td><%= contact.cell_phone %></td>
<td><%= contact.email %></td>
<td>
<% if current_user.admin? %>
<%= link_to "edit", contact, method: :edit %>
<% end %>
</td>
</tr>
<% end %>
The error I get is: undefined method `name' for nil:NilClass
What am I doing wrong? It seems to me like the way I'm referencing the field I'm not actually getting to the data in the Customers table but I'm not really sure. Did I build the relationship correctly in my models?
UPDATE to add controller code
class ContactsController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :new, :create]
def index
#contacts = Contact.paginate(page: params[:page])
end
def show
#contact = Contact.find(params[:id])
end
def new
#contact = Contact.new
end
def create
#contact = Contact.new(contact_params)
if #contact.save
flash[:success] = "Contact created!"
redirect_to #contact
else
render 'new'
end
end
def edit
#contact = Contact.find(params[:id])
end
def update
#contact = Contact.find(params[:id])
if #contact.update_attributes(contact_params)
flash[:success] = "Contact updated"
redirect_to #contact
else
render 'edit'
end
end
private
def contact_params
params.require(:contact).permit(:first_name, :last_name, :email, :address1,
:address2, :office_phone, :cell_phone, :website, :city, :zip, :facebook, :twitter)
end
end
class CustomersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :new, :create]
def index
#customers = Customer.paginate(page: params[:page])
end
def show
#customer = Customer.find(params[:id])
end
def new
#customer = Customer.new
end
def create
end
def edit
#customer = Customer.find(params[:id])
end
def update
#customer = Customer.find(params[:id])
if #customer.update_attributes(customer_params)
flash[:success] = "Customer updated"
redirect_to #customer
else
render 'edit'
end
end
private
def customer_params
params.require(:customer).permit(:name, :email, :address1,
:address2, :phone, :fax, :website, :city, :zip, :facebook, :duns_number)
end
end
EDIT:
This is my contact.html.erb form.
<%= form_for #contact, html: { class: "form-horizontal form-label-left" } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="form-group">
<%= f.label :first_name, nil, class: 'control-label col-md-3 col-sm-3 col-xs-12' %>
<div class="col-md-6 col-sm-6 col-xs-12">
<%= f.text_field :first_name, class: 'form-control col-md-7 col-xs-12' %>
</div>
</div>
<div class="form-group">
<%= f.label :last_name, nil, class: 'control-label col-md-3 col-sm-3 col-xs-12' %>
<div class="col-md-6 col-sm-6 col-xs-12">
<%= f.text_field :last_name, class: 'form-control col-md-7 col-xs-12' %>
</div>
</div>
<div class="form-group">
<%= f.label :customer_id, nil, class: 'control-label col-md-3 col-sm-3 col-xs-12' %>
<div class="col-md-6 col-sm-6 col-xs-12">
<%= select_tag :customer_id, options_for_select(Customer.all.collect {|c| [ c.name, c.id ] }), class: 'form-control' %>
</div>
</div>
<div class="form-group">
<%= f.label :office_phone, nil, class: 'control-label col-md-3 col-sm-3 col-xs-12' %>
<div class="col-md-6 col-sm-6 col-xs-12">
<%= f.text_field :office_phone, class: 'form-control col-md-7 col-xs-12' %>
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-md-offset-3">
<%= f.submit "Save changes", class: "btn btn-primary" %>
</div>
</div>
<% end %>
You are referencing it correctly.
It looks like your contact has not yet been saved to the database. This would cause the relation to not yet exist.
You would might need to be creating the relationship differently.
I usually do something like:
customer = Customer.create
customer.contacts << Contact.create({first_name: 'John', last_name: 'Smith'})
which creates the associations and commits to the DB right away. Then, in the same request, your contact's customer will be set and accessible.
You could also do this, but it's a little redundant:
customer = Customer.create
customer.contacts << Contact.create({first_name: 'John', last_name: 'Smith', customer: customer})
EDIT
It seems that perhaps you need to be assigning a customer to the contact when it is created/updated. In your Contact form, you'll likely need something like this (seeing your existing forms would help here):
<%= select_tag :customer_id, options_for_select(Customer.all.collect {|c| [ c.name, c.id ] }) %>
or (using simple_form):
f.input :customer_id, collection: Customer.all, selected: #contact.customer_id
# or more simply
f.association :customer
Or maybe a hidden form field if you know the Customer when building the form:
f.input :customer_id, as: :hidden, value: #customer.id
Then in your controller, add customer_id to the contact_params like this:
def contact_params
params.require(:contact).permit(
:first_name, :last_name, :email, :address1,
:address2, :office_phone, :cell_phone,
:website, :city, :zip, :facebook, :twitter,
:customer_id
)
end
Try .try() activesupport method:
<td><%= contact.customer.try(:name) %></td>
If contact.customer is nil (Contact doesn't belongs_to Customer), :name method wouldn't be invoked.
UPDATED Another hints:
a. That's a bad thing that you have a contact without customer. Consider to add this to your model:
class Contact < ActiveRecord::Base
...
validates :customer, presence: true
b. You can replace code like that:
<tr class="<%= cycle("even pointer", "odd pointer") %>">
with
<%= content_tag :tr, class: cycle('event pointer', 'odd pointer') %>
c. Replace this:
<%= contact.email %>
with this:
<%= mail_to contact.email, contact.customer.try(:name) %>
Generally this can help
For example, you have 2 tables City and Post, each post has city_id and you want to display in the views the name of the city associated with the post, you should call in the views the bloc then the name of the table then the name of column like that:
<% #post.each do |post| %>
<%= post.city.name %
<% end %>

Resources