Search by association in Rails 3 with MetaSearch - ruby-on-rails

I'm using MetaSearch gem in my Rails 3 project.
I have two models:
class Company < ActiveRecord::Base
belongs_to :city
end
class City < ActiveRecord::Base
has_many :companies
end
I have the action in CompaniesController:
def index
#search = Company.search(params[:search])
#companies = #search.all
end
The action's view contains:
= form_for #search do |f|
= f.label :city_id_equals
= f.select :city_id_equals
= f.submit 'Search'
I want a list with city names to be rendered and the opportunity to search the companies by city. But instead of the names and ids of the cities I have something like "City:0x00000102a20488" and the search doesn't work properly.
I think that the mistake is here: ":city_id_equals". How to make it correct?

The solution is found!
Instead of:
= f.label :city_id_equals
= f.select :city_id_equals
I should use:
= f.label :city_id_equals
= f.collection_select :city_id_equals, City.all, :id, :name, :include_blank => true

Not sure your question is really clear.
First of all, I'm guessing you have something like <City:0x00000102a20488>, which is the string representation of a ruby object. If you want to display the name of the city, city.name should make the trick (assuming you have a name member on the city!).
For the search, I don't really get what you are trying to do. What is :city_id_equals supposed to mean to you?

Related

Rails f.select Save Id an Name at the same time

I have a form with the f.select option. I want to add the Company ID and the Company Name when the company name is selected from the options. Is it possible to add multiple attributes in the f.select line of code? This is how my code looks:
<div class="field">
<%= f.label 'Client' %>
<%= f.select :client_id, Client.all.collect { |c| [ c.companyName, c.id ] } %>
I want to also assign the companyName to my :companyName attribute, but the id is the only thing that is being saved right now.
Thanks.
I think you can use associations for this. You should have 2 models as below.
class Company < ApplicationRecord
has_many :clients
end
class Client < ApplicationRecord
belongs_to :company
end
Your should use variable instead in views for rendering all clients list with this
<%= f.select :client_id, #clients.collect { |client| [ client.name, client.id] } %>
Controller:
#clients = Client.all
On Submit the client_id will be passed to controller. You can then find the company associated with the client and other logic.
client = Client.find(params[:client_id])
company = client.company
# etc ..
In the controller action where your form submits you can write before saving or updating record.
params[:your_object][:companyName]=Client.find_by(id: params[:your_object][:client_id]).companyName
Remember to a add params[:your_object][:companyName] to your strong params. e.g.
params.require(:your_object).permit(:client_id, ... , :companyName)
Before anything be sure your client_id is in same object and permitted and apply same to companyName attribute
Hope This Helps

Creating a form for a has_and_belongs_to_many relationship

I've read through a lot of posts regarding this topic, but not one actually provides a good answer.
I have a class A and a class B who are related through a has_and_belongs_to_many relationship.
class A < ApplicationRecord
has_and_belongs_to_many :bs
end
class B < ApplicationRecord
has_and_belongs_to_many :as
end
What I need is a form for class A showing a selection field with all the instances of B to select. Also, when editing and instance of A, the form should present a list of the related instances of B and a way to mark them for removal.
I have tried creating the list of existing instances by providing a hidden field with the id for each instance of B. And I have created a selection field using the select_tag. The code looked something like that:
= form_for #a do |f|
.field
= f.label :name
= f.text_field :name
.field
- #a.bs.each_with_index do |b, i|
= b.name
= hidden_field_tag "a[b_ids][#{i}]", b.id
.field
= select_tag "a[b_ids][]", options_from_collection_for_select(#bs, "id", "name")
.actions
= f.submit 'Save'
This worked just fine when creating the new instance of A. But when I tried to edit it, there seems to be a problem making the execution fall back to using POST instead of PATCH. And since with there is now route for POST when editing/updating this obviously ended in an exception.
So I wonder if there is any clean way to create the form I need?

Cocoon Show object instead value

My situation:
"app/models/aircraft.rb"
class Aircraft < ActiveRecord::Base
has_many :aircraft_crew_roles
has_many :crew_roles, through: :aircraft_crew_roles, class_name: 'CrewRole'
end
"app/models/aircraft_crew_role.rb"
aircraft_id
crew_role_id
class AircraftCrewRole < ActiveRecord::Base
belongs_to :aircraft
belongs_to :crew_role
accepts_nested_attributes_for :crew_role, reject_if: :all_blank
end
"app/models/crew_role.rb"
name
class CrewRole < ActiveRecord::Base
end
"app/views/aircrafts/_form.html.haml"
= simple_form_for(#aircraft) do |f|
= f.error_notification
= f.input :name
#crew
= f.simple_fields_for :aircraft_crew_roles do |cr|
= render 'aircrafts/aircraft_crew_role', :f => cr
= link_to_add_association 'add a Crew Role', f, :aircraft_crew_roles, partial: "aircrafts/aircraft_crew_role"
= f.button :submit
"app/views/aircrafts/_aircraft_crew_role.html.haml"
.nested-fields.crew-fields
#crew_from_list
= f.association :crew_role, as: :select, collection: CrewRole.all()
= link_to_add_association 'or create a new Role', f, :crew_role
= link_to_remove_association "remove Role", f
"app/views/aircrafts/_crew_role_fields.html.haml"
.nested-fields
= f.input :role
this is my current situation and almost everything work fine: I can add new crew members to the aircraft and this will create the corresponding entry in the aircraft_crew_role and crew_role tables and if I connect to the database I can see that all the entry are right ( I see all ID and the role in the crew_role table is the one I've used in the form) but if I try use the crew already saved with the previous aircraft the select is populated with object instead of string:
#<CrewRole:0x007fa90d2f8df8>
#<CrewRole:0x007fa90d2f8c90>
#<CrewRole:0x007fa90d2f8b28>
I've already used cocoon in many other places in the app and in all the other places it worked smoothly.
I've compared my code with the example on the cocoon repo but I can't find the problem
You are using simple_form's f.association which will try to guess how to present the CrewRole object. It looks for name, label or plain old to_s ... In your case it is a non-standard field role, so it will just convert the model to string (giving the result you got).
To solve this you would have to rename your column (a bit drastic, but maybe that is what you did when recreating the db?) or better, write something like
= f.association :crew_role, label_method: :role
See simple_form documentation for more info.
I have Absolutely no idea how but "simply" dropping and re creating the database now everything works smoothly.

can't get mongoid/rails field to accept input as array

I'm creating a Question/Answer model in a Mongoid/Rails project. I want users to create their own questions and then create possible answers: 2 answers or 3 answers or more. I've got the form so they can add as many questions as they want, but I get this error:
Field was defined as a(n) Array, but received a String with the value "d".
Not only am I not getting the array, but it's wiping out "a" "b" and "c" answers and only saving "d".
My model:
class Question
include Mongoid::Document
field :question
field :answer, :type => Array
end
The relevant section of _form.html.haml:
.field
= f.label :question
= f.text_field :question
%p Click the plus sign to add answers.
.field
= f.label :answer
= f.text_field :answer
#plusanswer
= image_tag("plusWhite.png", :alt => "plus sign")
.actions
= f.submit 'Save'
The jQuery that repeats the answer field when they need it:
$("#plusanswer").prev().clone().insertBefore("#plusanswer");
I've tried several of the solutions here involving [] in the field but getting nowhere.
Thanks much.
Two approaches:
One is to edit the form such that instead of returning back question[answer], it returns question[answer][] which will build answer to be an array.
EDIT: I'm reading your question closer and it seems like you have some JS dynamically rendering forms. In that case, setting the id with an empty bracket set [] at the end should turn the form object returned into an array
The other is to override the setter in the model to convert a string into an array. The safest way is to create a matching getter
class Question
field :answer, type: Array
def answer_as_string
answer.join(',')
end
def answer_as_string=(string)
update_attributes(answer: string.split(','))
end
end
Then use :answer_as_string in your form
If you don't want to do a lot wrangling back and forth of the values between javascript and your model and you understand how to use fields_for and nested attributes a better approach might be to make answers separate model and embed them in the question model as so:
class Question
include Mongoid::Document
embeds_many :answers
end
class Answer
include Mongoid::Document
field :content # or whatever you want to name it
end
Your form would look like this (pardon my HAML):
.field
= f.label :question
= f.text_field :question
%p Click the plus sign to add answers.
= f.fields_for :answers do |ff|
.field
= ff.label :content
= f.text_field :content
#plusanswer
= image_tag("plusWhite.png", :alt => "plus sign")
.actions
= f.submit 'Save'

Ruby/Rails: dynamically change attribute in shared partial

This should be a layup for someone...
I'm trying to change a form field's attribute depending on which controller/model is calling the partial containing the form fields...
The issue (below) is with parent_id... which references one of two columns in a dogs table. It needs to either be kennel_id or master_id depending on which view this partial is being rendered in.
Not comfortable enough, yet, with Ruby/Rails language/syntax/tools to dynamically change this without getting bogged down in if/else statements.
I'm calling a shared partial and passing in a local variable:
= render "dogs/form", :parent => #kennel
or
= render "dogs/form", :parent => #master
In the partial I'd like to:
= form_for ([parent, target.dogs.build]) do |f|
= render "shared/error_messages", :target => parent
.field
= f.label :name
= f.text_field :name
.field
= f.hidden_field :parent_id ### <= PROBLEM
.actions
= f.submit 'Save'
Just thinking out loud:
I don't know if the parent-models have the proper names for it, but you could do something like:
= f.hidden_field "#{parent.class.name.underscore}_id"
But that doesn't look right. So, why not pass it as an argument?
= render "dogs/form", :parent => #master, :foreign_key => :master_id
Or, create aliases on the dog model to handle some sort of dynamic delegation:
class Dog
def parent_id=(parent_id)
case parent.class
when Master then self.master_id = parent_id
when Kennel then self.kennel_id = parent_id
end
end
def parent_id
case parent.class
when Master then self.master_id
when Kennel then self.kennel_id
end
end
end
But that sucks too. Could the relation be polymorphic? Then you can leave out the switching.
class Dog
belongs_to :owner, :polymorphic => true
end
= f.hidden_field :owner_id
Just some ideas. Hopefully one of them makes sense to you...
Wow, my initial answer wasn't even close. I think what you'll want is a polymorphic association: http://guides.rubyonrails.org/association_basics.html#polymorphic-associations This way, the parent can be whatever class you need it to be.

Resources