Rails Select Drop Down with content from Controller not working - ruby-on-rails

I've got a list of items in a model, Tag, that I want to show in a drop down field. The user will select one, and it will be added to the Chat object. There is a 1:many relationship with Chat::Tags, stored in a Taggings table.
So--A user selects a Tag from the drop down list and clicks "Add Tag", and the Chat page is refreshed, with the new Tag added to the Chat page (and stored in the Taggings table as foreign keys to Chat and Tag).
Here's what I have...
chats_controller.rb:
def show
#chat = Chat.find params[:id]
#tags = Tag.order(:name)
end
def update
#chat = Chat.find params[:id]
tagging = #chat.taggings.create(tag_id: params[:tag_id], coordinator: current_coordinator)
flash[:success] if tagging.present?
end
And in show.html.haml:
.li
= form_for #chat, url: logs_chat_path(#chat), method: :put do |f|
= f.collection_select(:tag_id, #tags, :id, :name, include_blank: true)
= f.submit "Add Tag"
Right now, it returns the following error:
"exception": "NoMethodError : undefined method `tag_id' for #<Chat:0x000000073f04b0>",
--edit--
The taggings table is:
["id", "chat_id", "tag_id", "coordinator_id", "created_at", "updated_at"]
And rake routes shows:
logs_chats GET /logs/chats(.:format) logs/chats#index
POST /logs/chats(.:format) logs/chats#create
new_logs_chat GET /logs/chats/new(.:format) logs/chats#new
edit_logs_chat GET /logs/chats/:id/edit(.:format) logs/chats#edit
logs_chat GET /logs/chats/:id(.:format) logs/chats#show
PATCH /logs/chats/:id(.:format) logs/chats#update
PUT /logs/chats/:id(.:format) logs/chats#update
DELETE /logs/chats/:id(.:format) logs/chats#destroy

The reason this doesnt work is because the form is for #chat and chat doesn't have a method called tag_id. The way it's called in the form is by the use of the f object. If you want to change/update taggings in that form...
change your collection_select from this
= f.collection_select(:tag_id, #tags, :id, :name, include_blank: true)
to this
= collection_select(:taggings, :tag_id, #tags, :id, :name, include_blank: true)
and then in your controller change this
tagging = #chat.taggings.create(tag_id: params[:tag_id], coordinator: current_coordinator)
to this
tagging = #chat.taggings.create(tag_id: params[:taggings][:tag_id], coordinator: current_coordinator)

Related

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 %>

Limit scope on rails-jquery-autocomplete (rails3-jquery-autocomplete) gem - where clause issue

There is a recommended solution and it seems to work. The issue is in my where clause and I'm not sure what's wrong.
For reference, here is the solution(s):
https://stackoverflow.com/a/7250426/4379077
https://stackoverflow.com/a/7250341/4379077
I am trying to scope users that are members of the current_user's family tree memberships(branches) user's within my Nodes controller. This would normally be done using this code (current_user.family_tree.memberships).
Note I have successfully set this up to autocomplete showing all users (User.all):
In my routes:
resources :nodes do
get :autocomplete_user_first_name, :on => :collection
end
In my Node controller I have the following code:
autocomplete :user, :first_name, :extra_data => [:last_name, :email],
display_value: :full_name
And in my view I have the following form:
<%= form_for node do |f| %>
<%= f.label :user_tags %>
<%= f.autocomplete_field :user_tags, autocomplete_user_first_name_nodes_path, 'data-auto-focus' => true, value: nil %>
<%= f.submit %>
<% end %>
When I attempt to add the recommended solution to my nodes controller:
def get_autocomplete_items(parameters)
items = super(parameters)
items = items.where(:user_id => current_user.family_tree.memberships)
end
I get this message:
NoMethodError - super: no superclass method "get_autocomplete_items" for #<NodesController:0x007fc516692278>:
So, I found this article https://stackoverflow.com/a/18717327/4379077 and changed it to
def get_autocomplete_items(parameters)
items = active_record_get_autocomplete_items(parameters)
items = items.where(:user_id => current_user.family_tree.memberships)
end
It works, but I get the following error
PG::UndefinedColumn: ERROR: column users.user_id does not exist, so I changed the where clause to this :id => current_user.family_tree.memberships and I get this result
User Load (0.9ms) SELECT users.id, users.first_name, "users"."last_name",
"users"."email"
FROM "users" WHERE (LOWER(users.first_name) ILIKE 'mi%')
AND "users"."id" IN (SELECT "memberships"."id" FROM "memberships"
WHERE "memberships"."family_tree_id" = $1)
ORDER BY LOWER(users.first_name) ASC LIMIT 10 [["family_tree_id", 1]]
The issue is that I believe I need to get a collection within the membership model comparing the attribute membership.user_id to user.id. What am I doing wrong in my where clause?
Are Membership objects the same thing as Users?
if not, you need to get the user_id off the membership record
This line would need to change
# use pluck to get an array of user_ids.
items = items.where(:id => current_user.family_tree.memberships.pluck(:user_id))

Rails: how to get fields of rejected submit form?

I got one big form with many fields. There are multiple select_tag fields:
-(0..2).to_a.each do |id|
= select_tag('product[category_ids][]', options_from_collection_for_select(Category.all, :id, :name), :prompt=> '-- Select a Category --')
Problem: If the form is rejected upon submit, the :new action does not remember what is the previous selected values of select_tags.
Every other field reappears after submit (like :title, :description), but categories_id are lost.
Probable solution: We must add default selection to the select_tag in the options_from_collection_for_select method. How to get that category_id value? How can we access the fields of the previous form?
options_from_collection_for_select(Category.ordered, :id, :name, category_id)
You could store this data in the session and load it in the new action if it exists and clear that from the session.
That way anytime the fields reject the one that is not remembered loads into the session and is loaded into the select on the new action. Otherwise nothing is loaded when this session variable is blank.
Hope this helps.
In my form
#product.categories = []
but
#product.category_ids = [1,42,57]
So I added one messy if statement:
-if #product.category_ids.count == 0 #create new product
-(0..2).to_a.each do |id|
= select_tag('product[category_ids][]', options_from_collection_for_select(Category.all, :id, :name), :prompt=> '-- Select a Category --')
-else #edit old product, or fixing errors to previous submit
-#product.category_ids.each do |category_id|
= select_tag('product[category_ids][]', options_from_collection_for_select(Category.all, :id, :name, category_id), :prompt=> '-- Select a Category --')

Have a select box filled with names

In my view I have a form with a text_field_tag that takes an int, and returns only the timesheets whose timesheet.user_id match that int
<%= text_field_tag("user_id", params[:user_id]) %>
And then I have a bunch of users, these users have a name user.name and an id user.id.
I have a method in the controller called pending_approvals that when given the user id, narrows my list down to a specific users objects.
if params[:user_id].present?
#time_sheets = #time_sheets.joins(:user).where("users.id IN (?)", params[:user_id])
end
So what I am having an issue with, is I am not sure how to populate my select box with a list of users names. And then when submitted I need it to give the users id to that method. What is the best way of doing this?
If I understand correctly is you want a collection dropdown list to detail all users and thier id. You can do:
<%= collection_select :user, :user_id, #users, :name, :id, :prompt => true %>
Where :text_method is method which called on #users members will return text that you'd like to appear in dropdown.
The ApiDocs breaks it down, and this is how it is set up:
object = User
method = user_id
collection #users
value_method = id
text_method = name
option = prompt => true

How to send user.id with :user in params even though user.name is what is in the form drop down?

Currently, I have an action in my customers controller generating an array of names, #username_array, of all objects of class User with which to populate a drop down menu in a form that creates a new object of class Customer. The form element looks like this right now:
<%= f.select :user_id, #username_array %>
What I'd really like is for the id of the user to be sent into params[:customer][:user_id] instead of the name of that user that is chosen in the drop down. So in my create action in my customers controller I have the following code:
#customer = Customer.new(params[:customer])
#user = User.find_by_name(params[:customer][:user_id]) # where :user_id is actually currently the name selected from the drop down
#customer.user_id = #user.id
Is there an easier way of doing this?
Change your #username_array to include both the name and the id of the user:
Instead of:
["Bob","Sally","Dave"]
Make it:
[["Bob", 1],["Sally",2],["Dave",3]]
This could be accomplished by something like this:
#username_array = User.all.map {|user| [user.name, user.id]}
Then, f.select will display the name in the dropdown, but the actual value passed in through params[:customer][:user_id] will be the id of the user, which is what you want. With this in place, the following is all you need in the controller action code:
#customer = Customer.new(params[:customer])
You won't have to look up the user by name, the params hash will already have the correct id value.
Note that instead of making #username_array an instance variable you could just create a utility method in the helper for this controller, or the application helper:
def user_select
User.all.map {|user| [user.name, user.id]}
end
Then, in your view:
<%= f.select :user_id, user_select %>
If you put this in your application helper, you can use it everywhere and only have the code in one place (DRY).
you can do
#user = User.find_by_name(params[:customer][:user_id])
#user.customers.new(params[:customer])
or
#user = User.find_by_name(params[:customer][:user_id])
#customer = #user.customers.create(params[:customer])
but to do that you must have the relation (has_many, belongs_to,...)
or
Customer.new(params[:customer], :user_id => params[:customer][:user_id])
or
f.collection_select :user_id, #username_array, :id, :name

Resources