Merging Drop down from two Tables in Rails - ruby-on-rails

I like to know how to merge two table attributes and summarize them in a single drop down.
I tried to create a method in the create form helper which i referenced the attributes of the table.
_form.html.erb
<div class="field">
<%= form.label :Destinations %>
<%= form.collection_select(:destination_id, Destination.all, :id, destname_with_klm(#createform.destination), {}, { :multiple => false } ) %>
</div>
createforms_helper.rb
module CreateformsHelper
def destname_with_klm(f)
"#{f.Destination_name}.#{f.Destination_kilometre}"
end
end
NoMethodError in Createforms#new
Showing **/app/views/createforms/_form.html.erb where line #34 raised:
undefined method `Destination_name' for nil:NilClass

the error you are getting undefined method "Destination_name" for nil:NilClass is because the parameter (f) you pass is nil
However, I think you can update the model and make the code bit cleaner. (I had a look at the formatted suggested edit and gather this info)
#app/models/destination.rb
class Destination < ActiveRecord::Base
#other code
def destination_name_with_kms
# I believe the attribute names should be lowercase
"#{Destination_name}.#{Destination_kilometre}"
end
end
#in your view
<%= form.collection_select(:destination_id, Destination.all, :id, destination_name_with_kms, {}, { :multiple => false } ) %>
If you want to go one step further, I would recommend to use a decorator gem like
Draper, and move all the UI formatting to a decorator.

Related

Rails ActiveRecord::AssociationTypeMismatch - ActsAsTaggableOn::Tag(#755220) expected, got "" which is an instance of String(#7280):

I'm using the acts-as-taggable-on gem to add tags on my business + service models in my Rails 6 app in order to enable users to find whatever service/business they're seeking more easily. A service will have food-specific tags available if the business is a restaurant, and more general ones if it's another type of business. Whenever I try to create either a new business or a new service, I'm getting the same error:
ActiveRecord::AssociationTypeMismatch - ActsAsTaggableOn::Tag(#755220) expected, got "" which is an instance of String(#7280):
app/controllers/services_controller.rb:12:in `create'
Here is the relevant part of my Service model code:
class Service < ApplicationRecord
belongs_to :business
acts_as_taggable_on :tags
acts_as_taggable_on :food_taggings, :service_taggings
Here's the relevant part of my new service form:
<%= simple_form_for [#business, #service] do |f|%>
<%= f.input :food_taggings, collection: Service.foodlist, input_html: {multiple: true, id: "food_tagging_new", class: "select2"}, label: "Please add some descriptive tags to the dish that you're offering so that local users could find it more easily" %>
<%= f.input :service_taggings, collection: Business.offerings, input_html: {multiple: true, id: "service_tagging_new", class: "select2"}, label: "Please add some descriptive tags to the service that you're offering so that local users could find it more easily" %>
<%= f.button :submit, 'Submit', class: 'btn btn-primary'%>
</div>
<% end %>
Here's the relevant part of my services controller code:
def create
#service = Service.new(service_params)
if #service.save
flash[:notice] = "This service was successfully added!"
redirect_to #service
else
render "new"
end
end
private
def service_params
params.require(:service).permit( :tag_list, tag_list: [], food_taggings: [], service_taggings: [] )
end
And here are the params that go along with the create new service request:
{"authenticity_token"=>"kld9sOSfro/nrINxQdKpXCZnxt6Cjb6TIw+jcjW5XmpUhvfm767dPXStOGB2vEBbckZvb87uKXlZo2KGjAo8vA==", "service"=>{"name"=>"", "description"=>"", "price_cents"=>"", "food"=>"0", "food_taggings"=>[""], "service_taggings"=>[""]}, "commit"=>"Submit", "controller"=>"services", "action"=>"create", "business_id"=>"5"}
How would I go about fixing this issue so that both of the models can get created successfully? I was already able to create some seeds for both without including any tags successfully, and I'm not sure exactly what Rails is expecting now?
To recap what acts_as_taggable_on is doing, say you declare a single taggable attribute:
class Service < ApplicationRecord
acts_as_taggable_on :tags
end
The gem does two things:
It dynamically creates an association (i.e., has_many/belongs_to) between your class and ActsAsTaggableOn::Tag, which is how the gem models tags you define. When you access tags on a instance of Service, you get an array of these Tag objects like you would with any has_many association.
It also creates a friendly convenience wrapper called tag_list (note: singluarized), which is the main way the gem expects you to interact with tags. Calling this will do the work of querying the associated Tag objects and return you a nice array of strings. Or you can assign it an array of strings, which get parsed into Tag objects.
In your form and controller, you are using the raw association references (food_taggings and service_taggings). Thus when your form POSTs, Rails properly raises an error because it is expecting those parameters to be arrays of Tag objects not arrays of strings.
If you change your form to use the convenience wrapper names for the form fields, the gem will properly parse the array of strings in your params and create the associated objects:
<%= simple_form_for [#business, #service] do |f|%>
<%= f.input :food_tagging_list, ... %>
<%= f.input :service_tagging_list, ... %>
...
<% end %>
Don't forget to alter your permitted parameters on the controller as well:
def service_params
params.require(:service).permit(tag_list: [],
food_tagging_list: [],
service_tagging_list: [])
end
Try adding include_blank: false in your form input options. I think Rails gives you this error because it will always send "" (empty string) from the taggings form.
<%= f.input :food_taggings,
collection: Service.foodlist,
input_html: {
multiple: true,
id: "food_tagging_new",
class: "select2"
},
include_blank: false # Add this
label: "Please add some descriptive tags to the dish that you're offering so that local users could find it more easily"
%>

How do I call the name of a user when they belong to a model

I have two models, Chasing and User, a chasing belongs_to :user and a user has_many :chasings.
I created a migration for linking the two models together:
class AddUsersToChasings < ActiveRecord::Migration
def change
add_reference :chasings, :user, index: true, foreign_key: true
end
end
I have a controller for creating new users which I then want to be able to assign to chasings. I currently have this code in my chasings form for selecting the user:
<%= f.select :user_id, options_for_select(User.all.map {|c| [c.name, c.id]}), { :include_blank => "Please select user"}, {:class => "form-control"} %>
This seems to do the trick, after calling Chasing.first in rails console I can see the chasing now has user_id relevant to the user I picked. I can also run Chasing.first.user.name to give me the name of the user who is associated with the chasing. I'm wanting to show this name in my index view, the code I currently have for this is:
ChasingsController:
def index
#chasing = Chasing.all
end
Index view:
<% #chasing.each do |chasing| %>
<%= chasing.user %>
<% end %>
This shows a random string (seems to change every time I update a chasing - #<User:0xf5b0ba8> for example). when I change this to chasing.user.name I get 'undefined method `name' for nil:NilClass'.
Is there a way I can call the name for my view?
EDIT:
As per NickM's comment below I had chasings without users assigned to them causing active record to throw the error.
Looks like you have some Chasing objects in your database without user_ids. You can test by doing <%= chasing.user.name if chasing.user %>

undefined method for text_field in ruby on rails

<%= f.text_field :quantity_available, :readonly => "readonly",:class=>"mg-text-field" %>
error:
undefined method `quantity_available' for #<:0xaf32b824>
In the new form I have shown "quantity_available" whose value I am getting through jquery and this field is only for displaying purpose so this has not been saved in model but I want to do same in edit form in which I am getting error as
how to resolve this?
You can define the field in the Model without it needing to be a persisted column in the table.
class Model < ActiveRecord::Base
attr_accessor :quantity_available
# other stuff here
end
For that purpose you can use text_field_tag. For more check on http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html
<%= text_field_tag 'quantity_available',nil, class: "mg-text-field", readonly: true %>

How to handle data from nested forms in Rails 4 with cocoon gem?

I am using Cocoon gem to do nested forms.
I have models like that:
# request.rb
has_many :filled_cartridges, inverse_of: :request, dependent: :destroy
accepts_nested_attributes_for :filled_cartridges, :reject_if => :all_blank, allow_destroy: true
#filled_cartridge.rb
belongs_to :request
Inside of my form_for #request i have nested form like that:
<div id="filled_cartridges">
<%= f.fields_for :filled_cartridges do |filled_cartridge| %>
<%= render 'filled_cartridge_fields', f: filled_cartridge %>
<% end %>
<div class="links">
<%= link_to_add_association 'add', f, :filled_cartridges %>
</div>
Where filled_cartridge_fields partial is like that:
<fieldset>
<%= f.text_field :cartridge_id %>
<%= f.hidden_field :_destroy %>
<%= link_to_remove_association "remove", f %>
</fieldset>
When i click on "add" it adds one more . When clicking on "remove" it removes that .
When i submit form the params for nested form look like that:
filled_cartridges_attributes: !ruby/hash:ActionController::Parameters
'0': !ruby/hash:ActionController::Parameters
cartridge_id: '12'
_destroy: 'false'
'1429260587813': !ruby/hash:ActionController::Parameters
cartridge_id: '2'
_destroy: 'false'
How do i access these params, and how to save them. How to traverse over these params and save them, or do Cocoon gem has some built in functionality? And finally how to check if these params are set? Since it is nested, it tricks me.
EDIT: My request_controllers#create:
def create
#request = Request.new( request_params )
# code for handling Request model
# here i want to handle nested model too (filled_cartridge)
#request.save
if #request.save
flash[:success] = "Заявка была добавлена"
redirect_to #request
else
render 'new'
end
end
EDIT2: my strong params:
def request_params
params.require(:request).permit(:name, :address, :phone, :mobile, :type, :description, :priority, :responsible, :price, :payed, :date, filled_cartridges_attributes: [:cartridge_id, :_destroy], :stype_ids => [], :social_media =>[])
end
In a recent project using cocoon I had to access the params of the attributes about to be saved. I figured a code in my create action in my controller. The trick is to understand how to retrieve the key of the hash of the attribute that is about to be saved. The key of the hash is that number '1429260587813' that is in your params
...
'1429260587813': !ruby/hash:ActionController::Parameters
cartridge_id: '2'
_destroy: 'false'
So you need to create a loop in your create action to retrieve this key using ruby hash method "keys". I do a loop because when using cocoon dynamic nested field I might create more than one nested attributes at once so it means more than one key to retrieve.
Here is a the code that worked for me, read my comments which explains the different steps of this code. I hope it will help you to adapt it to your needs.
#Here I just initialize an empty array for later use
info_arr = []
#First I check that the targeted params exist (I had this need for my app)
if not params[:recipe]["informations_attributes"].nil?
#z variable will tell me how many attributes are to be saved
z = params[:recipe]["informations_attributes"].keys.count
x = 0
#Initiate loop to go through each of the attribute to be saved
while x < z
#Get the key (remember the number from above) of the first hash (params) attribute
key = params[:recipe]["informations_attributes"].keys[x]
#use that key to get the content of the attribtue
value = params[:recipe]["informations_attributes"][key]
#push the content to an array (I had to do this for my project)
info_arr.push(value)
#Through the loop you can perform actions to each single attribute
#In my case, for each attributes I creates a new information association with recipe
#recipe.informations.new(title: info_arr[x]["title"]).save
x = x +1
end
end
This work to access cocoon nested attribute content and apply actions based on your need. This worked for me so you should be able to use this sample code and adapt it to your need.

Rails Parse Form Input

I'm using a form to transfer some data from one part of a controller to another (new to create), but I'm having some trouble with it. When I try to get the data after submitting the form, it just gives me a nil value.
Here's the form code:
<%= f.hidden_field :owner_id, :value => #tool.user_id %>
<%= f.hidden_field :tool_id, :value => #tool.id %>
<%= f.hidden_field :borrower_id, :value => current_user.id %>
And this is the create action in the controller:
def create
render text: params[:rental_agreement].inspect
#rental_agreement = RentalAgreement.create
#rental_agreement.owner_id = params[:owner_id]
# render text: #rental_agreement.inspect
end
When I hit the "Submit" button on the form, I see this:
{"owner_id"=>"3", "tool_id"=>"1", "borrower_id"=>"4"}
That's fine, but when I change which inspection renders (comment out the top line, uncomment the bottom), all it displays is:
#
And if I look in the Rails console at this object, all of the fields in it are nil (except the id and created_at fields).
I'm just trying to figure out how to assign the variables from the form (owner_id, tool_id, and borrower_id) to the rental_agreement variable. Any help is much appreciated!
Your create method seems wrong. Try this.
def create
#rental_agreement = RentalAgreement.new(params[:rental_agreement])
#rental_agreement.save
end

Resources