Rails has_many update with empty array - ruby-on-rails

There is the following form code:
= form_for #task, html: { class: 'form-horizontal' } do |f|
.form-group
.col-sm-9.col-sm-offset-3
= render partial: 'shared/form_errors', locals: { subject: #task }
.form-group
label.col-sm-3.control-label for='title' Title
.col-sm-9
= f.text_field :title, class: 'form-control', placeholder: 'Title'
.form-group
label.col-sm-3.control-label for='description' Description
.col-sm-9
= f.text_area :description, class: 'form-control', placeholder: 'Description'
.form-group
label.col-sm-3.control-label Teams
.col-sm-9
ul
- Team.all.each do |t|
li
= check_box_tag "team_ids", t.id, #task.teams.include?(t), name: 'task[team_ids][]'
= t.name
.form-group
.col-sm-9.col-sm-offset-3
= f.submit 'Save', class: 'btn btn-success'
As you can see I can select team for my task through checkboxes. My controller:
def update
#task = Task.find(params[:id])
if #task.update(task_params)
redirect_to tasks_path, flash: { alert: TASK_UPDATING_MESSAGE }
else
render 'edit'
end
end
private
def task_params
params.require(:task).permit(:title, :description, team_ids: [])
end
It works good if I update task with some checked teams; but also I want to have ability to check no teams and update taks with empty array of teams. But in this case tasks_params doesn't have team_ids array, and updating doesn't work. How can I fix it? Thanks!

My understanding is that when you submit your form with nothing checked, you have params[:task][:team_ids] = nil.
You can try something like:
def task_params
params[:task][:team_ids] = [] if params[:task][:team_ids].nil?
params.require(:task).permit(:title, :description, team_ids: [])
end

You can do it using collection_check_boxes, just replace the list of teams with:
ul
= f.collection_check_boxes :team_ids ,Team.all, :id, :name do |b|
= content_tag :li, raw("#{b.label { b.check_box } }" + b.object.name)
And this will do the trick.
Note: With this Rails add a hidden field, which fix your issue, also you will fix it only with this:
<input type="hidden" name="task[team_ids][]" value="" autocomplete="off">

Related

rails: Is it possible that my receiver_id failling to be picked?

I am implementing a messaging solution for my rails app, I keep get the following error.
PG::InvalidTextRepresentation - ERROR: invalid input syntax for integer: ""
LINE 1: ...rsations" WHERE ((sender_id = 3 AND receiver_id = '') OR (se...
class MessagesController < ApplicationController
def create
if current_user.id == message_params[:receiver_id]
redirect_to request.referrer, alert: "You cannot send a message to yourself"
end
conversation = Conversation.where("(sender_id = ? AND receiver_id = ?) OR (sender_id = ? AND receiver_id = ?)",
current_user.id, message_params[:receiver_id],
message_params[:receiver_id], current_user.id
).first
if !conversation.present?
conversation = Conversation.create(sender_id: current_user.id, receiver_id: message_params[:receiver_id])
end
#message = Message.new(user_id: current_user.id,
conversation_id: conversation.id,
content: message_params[:content]
)
if #message.save
format.html { redirect_to request.referrer, notice: 'Message was successfully sent.' }
else
format.json { render json: request.referrer.errors, status: :unprocessable_entity }
end
end
Conversation model.
class Conversation < ApplicationRecord
belongs_to :sender, class_name: "User"
belongs_to :receiver, class_name: "User"
def last_message
message = Message.where(conversation_id: self.id).last
if message.present?
return message
else
return Message.new updated_at: Time.now
end
end
end
That happens because the value you're passing for reciever_id is an empty string, but the data type of that column in your database is an integer.
You can use or to make the query, but it'll transform your empty string to nil:
reciever_id = message_params[:reciever_id]
Conversation.where(sender_id: current_user.id, reciever_id: reciever_id)
.or(Conversation.where(sender_id: reciever_id, reciever_id: current_user.id))
Anyway, you might want to check what you're receiving in order to do the query you're performing. It can be assigning default values, returning early, adding constraints to your routes, etc.
Pasting the form directly works but putting it on the partial does not, i.e below this works.
- if current_user.id != profile.user.id
%small
%button.btn.btn-outline-light{"data-target" => "#modal_large", "data-toggle" => "modal", :type => "button"}
Send Message
= simple_form_for Message.new do |f|
= f.error_notification
= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present?
.form-inputs
.row
.col
= f.hidden_field :receiver_id, value: profile.user.id
= f.input :body, autofocus: true, label: "Type Your Message Below"
.form-actions
.row
.col
= f.button :submit, "Send Message", class: "btn btn-primary btn-lg mt-2 float-right"
= render partial: "message", locals: { user: profile.user }
This does not work..
#modal_large.modal.fade{"aria-hidden" => "true", "aria-labelledby" => "modal_large", :role => "dialog", :tabindex => "-1"}
.modal-dialog.modal-lg{:role => "document"}
.modal-content
.modal-header
%h5.modal-title Send a New Message
%button.close{"aria-label" => "Close", "data-dismiss" => "modal", :type => "button"}
%i.ti-close.font-size-14
.modal-body.py-4
= simple_form_for Message.new do |f|
= f.error_notification
= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present?
.form-inputs
.row
.col
= f.hidden_field :receiver_id, value: user.id #profile.user.id
= f.input :body, autofocus: true, label: "Type Your Message Below"
.form-actions
.row
.col
= f.button :submit, "Send Message", class: "btn btn-primary btn-lg mt-2 float-right"
The specific problem is on this line below.
= render partial: "message", locals: { user: profile.user }

Unable to autoload constant Controller

I have a form that I am using for new and edit, and the functionality for index and clicking for a new form and edit works, but when I go to create or update the form returns a load error to another controller.
The controller is PathCreationsController in system and it wants to use the creations controller in another place and it wants to use it to define it..which is weird because I don't have anything set to do that.
I tried adding a url to the form and setting the method to put but when I do that to try and force the controller to work correctly it sets all the params to null in the database so I assumed thats not a valid way to fix this.
Here is the controller:
class System::PathCreationsController < ApplicationController
def index
#paths = Path::Account.all
end
def new
#paths = Path::Account.new
end
def edit
#paths = Path::Account.friendly.find(params[:id])
end
def create
#paths = Path::Account.new
if #paths.save
redirect_to system_path_creations_path(#paths)
end
end
def update
#path = Path::Account.find_by(slug: params[:id])
if #path.update
redirect_to system_path_creations_path(#path)
end
end
end
Here is the form:
= form_for #paths do |f|
%br
.form-group
= f.label :name, class: 'control-label'
= f.text_field :name, class: 'form-control'
.form-group
= f.label :slug, class: 'control-label'
= f.text_field :slug, maxlength: 28, class: 'form-control'
.form-group
%p.text-muted Click to upload new icon.
.fileinput.fileinput-new{"data-provides" => "fileinput"}
%div
.fileinput-thumbnail.thumbnail{style: 'max-width: 100%;'}
.fileinput-preview{data: {trigger: "fileinput"}, style: 'max-width: 100%;'}
= image_tag #firms.try(:logo).try(:present?) ? #life_event.try(:logo).try(:url) : asset_path('/path.svg')
%div
%span.btn.btn-default.btn-file.btn-sm{style: 'display: none;'}
= f.file_field :logo, class: 'file'
= f.hidden_field :logo_cache
.form-group
= f.label :user_id
= f.select :user_id, User.all.collect {|u| [#{u.email}", u.id] }
= f.submit class: 'btn btn-primary btn-sm'
In the create action you never set update the parameters on the model
def create
#paths = Path::Account.new(path_params)
if #paths.save
redirect_to system_path_creations_path(#paths)
end
end
you will also need to add
def path_params
params.require(:path_account).permit(:name, :slug, :other, :params, :to, :permit)
end

Create action not being called in form

I've just started a new app where I want to take a postcode in a form and save it to the database. My problem is that the create action doesn't seem to be being called no matter what I try.
Routes:
root 'postcodes#new'
resources :postcodes, only: [:new ,:create]
Controller: postcodes_controller.rb
class PostcodesController < ApplicationController
def new
#postcode = Postcode.new
end
def create
#postcode = Postcode.new(postcode_params)
if #postcode.save
flash[:success] = 'Success'
else
flash[:error] = 'Error'
end
end
private
def postcode_params
params.require(:postcode).permit(:code)
end
end
Model: postcode.rb
class Postcode < ApplicationRecord
validates :code, presence: true, uniqueness: true
end
View: postcodes/new.haml
.container
%form
%fieldset.form-group
= form_for #postcode do |f|
= f.label :postcode
= f.text_field :code, placeholder: 'Example Postcode', class: 'form-control'
= f.submit 'Submit', class: 'btn btn-primary'
I've attempted to pass more options in the form_for such as the method and action and now I have a feeling it's a routing error.
Any help will be appreciated.
Thanks.
I believe the problem you are experiencing is a result of your HAML.
You do not need to use, nor should you use, a form HTML element outside the form_for method call.
The form_for method will handle generating this HTML element/tag for you.
You have:
.container
%form
%fieldset.form-group
= form_for #postcode do |f|
= f.label :postcode
= f.text_field :code, placeholder: 'Example Postcode', class: 'form-control'
= f.submit 'Submit', class: 'btn ban-primary'
Which outputs an empty <form> element.
You should have:
.container
= form_for #postcode do |f|
%fieldset.form-group
= f.label :postcode
= f.text_field :code, placeholder: 'Example Postcode', class: 'form-control'
= f.submit 'Submit', class: 'btn ban-primary'
That should generate a proper <form> tag with the required action and method attributes populated with the right URL and 'post' so that your create action is called.

Rails Controller Triggering Both Branches Of If-Else Statement

I'm new here so I hope it's appropriate for new accounts to ask questions straight away. I've been working with Rails for sometime now and usually I'm pretty good at researching and solving my own problems - but this one has had me stumped for a few days now.
I have a create action being called in a controller that contains an if-else statement that is conditional based on a check_box post parameter. I can see that the parameter is being posted to the controller so the statement should be able to correctly branch but something strange is happening. The controller executes both branches of the statement, but because my parameters are trimmed depending on that check_box, the second branch always errors out. I'm fairly confident this has little to do with routes.
Please see my code below:
Controller:
def create
#quote = Quote.find(params[:quote_id])
if params[:quote_item][:custom] == 1
#quote_item = #quote.quote_items.new(quote_item_params)
#quote_item.rate = nil
#quote_item.custom = true
#quote_item.unit_price = params[:quote_item][:unit_price]
#quote_item.rate_name = params[:quote_item][:title]
else
#quote_item = #quote.quote_items.new(quote_item_params)
#quote_item.custom = false
#rate = Rate.find(params[:quote_item][:rate_id])
#quote_item.unit_price = #rate.price
#quote_item.rate_name = #rate.product.name
end
respond_to do |format|
if #quote.save
format.html { redirect_to #quote, notice: 'Quote item was successfully added.' }
format.json { render :show, status: :created, location: #quote }
else
format.html { redirect_to #quote }
format.json { render json: #quote.errors, status: :unprocessable_entity }
end
end
View:
<% if #rates.any? %>
<%= bootstrap_form_for([#quote, #quote_item], layout: :inline) do |f| %>
<%= f.text_field :title, class: 'input-sm', hide_label: true, :placeholder => "Line Title" %>
<%= f.select(:rate_id, #rates.collect {|r| [r.select_summary_text, r.id ] }, { hide_label: true }, { :class => 'input-sm' }) %>
<%= f.number_field :quantity, class: 'input-sm', hide_label: true, :min => 1, :length => 2, :value => 1 %>
<%= f.text_field :unit_price, class: 'input-sm', hide_label: true, :min => 1, :length => 2, :prepend => "$" %>
<%= f.text_field :note, class: 'input-sm', hide_label: true, :placeholder => "Note (Optional)" %>
<%= f.submit "Add Quote Item", class: 'btn btn-sm btn-default' %>
<%= f.check_box :custom, label: "Override" %>
<% end %>
<% else %>
<div class="well well-sm"><i class="fa fa-usd"></i> No pricing for this customer has been set. Set product pricing for this jobs customer <%= link_to user_path(#quote.job.user) do %>here.<% end %></div>
<% end %>
My create method errors out here:
#rate = Rate.find(params[:quote_item][:rate_id])
With:
ActiveRecord::RecordNotFound (Couldn't find Rate with 'id'=):
app/controllers/quote_items_controller.rb:19:in `create'
This error is correct though, because the rate ID isn't processed in first branch of the if-else statement. I've tried different check_box form fields, directly overriding 'custom' and both branches still run.
Any help here is greatly appreciated!
The params hash contains strings.
Try swapping:
if params[:quote_item][:custom] == '1'
for your original:
if params[:quote_item][:custom] == 1

Value not getting stored in rails instance variable

I have a simple form which records Payments received :
<label>Client Name*</label>
<%= f.collection_select :client_id, Client.all, :id, :name, {prompt:"Select Client"},{ class: "form-control"} %>
<label>Service Name</label>
<%= f.collection_select :service_id, Service.all, :id, :name, {prompt: "Select Service"},{ class: "form-control"}%><label>Payment Amount</label>
<%= f.text_field :amount, placeholder: "Enter the amount received",class: "form-control" %>
<label>Payment Date</label> <br/>
<%= f.date_select :recieved_date, placeholder: "Enter the payment date",class: "form-control" %><br/>
<br/>
<%= f.submit "Submit", class: "btn btn-success" %>
<% end %>
The values are then passed on the controller:
def create
#payment = Payment.new(payment_params)
order = Order.where("client_id = ? and service_id = ?", payment_params[:client_id], payment_params[:service_id]).pluck(:id)
#payment.order_id = order[0]
if #payment.save
redirect_to new_payment_path, notice: "Successfully created Payment!"
else
render action: 'new'
end
end
As you can observe, the line
order = Order.where("client_id = ? and service_id = ?", payment_params[:client_id], payment_params[:service_id]).pluck(:id) attempts to store the order_id based on the client_id and service_id. However this is not working and the order object is getting saved with a nil value when being saved (when the validation to check for order_id is removed that is)
Why is this ? any hints please

Resources