Updating a rails attribute through a model association - ruby-on-rails

I have two models shop and user. Shop has_many Users and User has_one Shop. I'm trying to create a button on shop/show that allows a user to choose its shop. The button should send the parameter shop_id to Users_Controller#update_shop which then changes User.shop_id to the id of the shop on the page.
The current method in Users_Controller#update_shop is the following:
def update_shop
#user = User.find(params[:id])
#user.update_attributes(shop_id: params[:shop][:id])
flash[:success] = "Added Shop!"
end
And the button on show/shop is this:
<%= form_for User.update_shop, remote: true do |f| %>
<%= f.hidden_field :shop_id, value: #shop.id %>
<%= f.submit 'Add As Your Shop', :class => 'button blue-button' %>
<% end %>
I'm getting the error NoMethodError in ShopsController#show undefined methodupdate_shop' for #`. The method is defined in the Users controller though.
I understand there is probably a more efficient way to update User.shop_id through the association, so tips on doing that or getting this to work are greatly appreciated.

I think it's better to have a link with POST method in place of form:
<%= link_to 'Add As Your Shop', update_shop_url(id: #user.id, shop_id: #shop.id, class: 'button blue-button', data: { method: 'post' } %>
With this setup you should change controller method as well:
def update_shop
...
#user.update_attributes(shop_id: params[:shop_id])
...
end

Related

Search form Couldn't find User with 'id'=

I need to create search form to search for all the cases pt_name of the user
I got this error
Couldn't find User with 'id'=
In cases controller
def index
#user =User.find(params[:id])
#cases=#user.cases
if params[:search]
#search_term = params[:search]
#cases= #user.cases.casesearch_by(#search_term)
end
end
in case model
class Case < ActiveRecord::Base
belongs_to :user
def self.casesearch_by(search_term)
where("LOWER(pt_name) LIKE :search_term OR LOWER(shade) LIKE :search_term",
search_term: "%#{search_term.downcase}%")
end
end
in cases index.html.erb
<%= form_for "",url: cases_path(#user.id), role: "search", method: :get ,class: "navbar-form navbar-right" do %>
<%= text_field_tag :search, #search_term,placeholder: "Search..." %>
<% end %>
The problem is the first line in your controller.
When the form is submitted it's going to cases_path(#user.id) - that's what you specified in your form.
If you're checking with rails routes you'll see that cases_path is actually going to "/cases" (I am assuming you did not overwrite it) and that there isn't any placeholder for an id (like it would be for the show action for example which goes to "/cases/:id".
Now you still specify #user.id in cases_path(#user.id) and then you try to find a user with the id from the params. But if you check your params once you arrived in the controller (with binding.pry or other tools), you will see there is no key :id in the params. You can also check the url it is going to, I believe it will look something like this: "/cases.1".
You can solve that by changing the path to
cases_path(user_id: #user.id)
This way you add a new key value pair to the params hash and then in your controller you need to change it accordingly:
#user =User.find(params[:user_id])
You can also add a hidden field into your form in order to pass along the user id:
<%= form_for "", url: cases_path, role: "search", method: :get, class: "navbar-form navbar-right" do %>
<%= text_field_tag :search, #search_term,placeholder: "Search..." %>
<%= hidden_field_tag :user_id, #user.id %>
<% end %>
And then retrieve it in the controller.
To check your params that you get in the controller action use a gem like pry byebug or just the keyword raise and then inspect the params variable.

Redirecting to "show" view of a model object when searched by attributes (NOT id)

I have a form where users look for a particular bill by some attributes of that bill, namely the "Congress Number", "Bill Type", and "Bill Number", as in 114-H.R.-67 . I want to "show" the appropriate bill, but to do that I have get the appropriate bill model in a separate action which I've called "find_by_attributes". Inside this action I perform:
#bill = Bill.find_by( params ).first
which correctly acquires the appropriate bill's id.
Now I simply want to redirect to the "show" method of this bill, as in the url
".../bills/[#bill.id]"
As of right now, at the end of my "find_by_attributes" action I do
redirect_to bills_path(#bill)
which correctly loads the show.html.erb with #bill, but does not change the url (the url is still shows the "find_by_attributes" action followed by a long query-string, instead of the clean "/bills/[:bill_id]".
How can I restructure my code to achieve the neat redirect that I desire?
Full code below:
THE FORM
<%= form_tag("bills/find_or_create", :method => :get ) do |f| %>
<%# render 'shared/error_messages', object: f.object %>
<%= fields_for :bill do |ff| %>
<%= ff.label :congress, 'Congress (i.e. 114)' %>
<%= ff.number_field :congress, class: 'form-control' %>
<%= ff.select :bill_type, options_for_select(
[['House of Representatives', 'hr'],
['Senate', 's'],
['House Joint Resolution', 'hjres'],
['Senate Joint Resolution', 'sjres'],
['House Concurrent Resolution', 'hconres'],
['Senate Concurrent Resolution', 'sconres'],
['House Resolution', 'hres'],
['Senate Resolution', 'sres']]
)
%>
<%= ff.label :bill_number, 'Bill number (i.e. 67)' %>
<%= ff.number_field :bill_number, class: 'form-control' %>
<% end %>
<%= submit_tag "Submit", class: "btn btn-primary" %>
<% end %>
THE CONTROLLER ACTIONS
def find_by_attributes
#bill = Bill.where(bill_params).first_or_create(bill_attributes)
redirect_to bills_path(#bill)
end
def show
puts bill_params
if params[:bill]
#bill = Bill.where(bill_params).first_or_create do |bill|
bill.attributes = bill_attributes
end
else
#bill = Bill.find(params[:id])
end
#subjects = Subject.where("bill_id = ?", #bill[:id])
#bill_comments = Comment.where("target = ?", #bill[:id])
end
ROUTES FILE
...
resources :bills do
get :find_by_attributes
end
...
EDIT
I make use of the turbolinks gem in my rails application.
the thing I see here is that you are calling to
redirect_to bills_path(#bill)
that in theory is not the show path, you just need to remove the "s"
redirect_to bill_path(#bill)
and as a side comment, in this line, you don't need the first part, because find_b, finds the first record matching the specified conditions, you can remove that part.
#bill = Bill.find_by( params )

custom action submitting multiple forms in Rails

So I have this structure of application: a Game model which has many Allies and many Enemies.
I want to create a custom action for Game dedicated to create and submit enemies and allies.
So in the view I will have 2 fields_for that you can submit at the same time.
I have never created custom routes and actions or submitted 2 children forms in the same page.
Anyone know how I could do this ? Thanks
routes.rb
#this route shows the form
get 'create-players/:id', to 'game#new_players', as: :new_players
# this route recieves the form post submission
post 'create-players/:id', to 'game#create_players', as: :create_players
app/controllers/game_controller.rb:
def new_players
#game = Game.find(params[:id])
end
def create_players
#do whatever you want with the params passed from the form like
#allies = Ally.create(game_id: params[:id], name: params[:ally_fields][:name])
#enemies = Enemy.create(game_id: params[:id], name: params[:enemy_fields][:name])
#game = Game.find(params[:id])
end
app/views/game/new_players.html.erb:
<%= form_tag(create_players_paths, #game.id), method: 'POST') do %>
<% #...fields you have on models, perhaps %>
<% fields_for :ally_fields do |f|
<%= f.text_field :name, nil, placeholder: "Ally name", required: true
<% end % >
<% fields_for :enemy_fields do |f|
<%= f.text_field :name, nil, placeholder: "Enemy name", required: true
<% end % >
<%= submit_tag "create players", class: "submit" %>
<% end %>
app/views/game/create_players.html.erb:
<h1> Woah an allie and an enemy have been added to game <%= #game.id %></h1>
<p> Lets see some blood!</p>
Of course, you should enforce verifications on the input and before processing the post submission. Usually you'll want to use established relationships between objects, so that you can do on the view #model = Modelname.new then, form_for #object and have validations and error messages accessible in a much cleaner way.

Select_tag login

I would like to have a drop down menu with a list of all the user names in the db. From there, I would like the user to choose his/her name and be able to click login and be taken to their respective page. At this point, a password is not needed. Currently, I have the following:
controller:
def login
#user = User.new
#users = User.all
# #user = User.find_by_id(:id)
# redirect_to user_path(#user)
end
view:
<%= form_for #user, url: '/login', html: {method: 'get'} do |f| %>
<%= f.label "Name" %>
<br/>
<%= select_tag :user, options_for_select(#users) do |users| %>
<%= link_to users.name, users %>
<% end %>
<br/>
<br/>
<%= f.submit 'Login' %>
<% end %>
I cannot seem to link the user to their path and also, i want to show the users name in the drop down menu. Currently, it shows a hexidecimal pointer.
Thank you in advance.
You shouldn't be making a new User object here: you just want to load one out of the database. What you want to do in the controller is just to set current_user to be one of the existing users, right?
Also you've got the form submitting back to the action which loads the form in, which seems weird. I would make it submit to a new action, like "set_current_user" which is a POST action.
in your login template:
<%= form_tag '/set_current_user' do %>
<%= f.label "Name" %>
<br/>
<%= select_tag "user_id", options_for_select(#users.collect{|user| [user.name, user.id] } %>
<br/>
<br/>
<%= submit_tag 'Login' %>
<% end %>
in the controller (you'll need to amend routes.rb to make the '/set_current_user' go to this action) you then need to set something which will keep the user logged in. The traditional way to do this is via session[:user_id], and to have a method current_user which uses this.
def set_current_user
session[:user_id] = params[:user_id]
redirect_to "/" and return
end
Your initial approach is reminiscent of how this sort of thing is normally handled, wherein you do have a form_for, but it's for a UserSession object rather than a User object.

Ruby on rails adding users to groups

I am building a social networking site with user, school, and schoolgroup models. The users join, and have different roles in, the schools through the has_many through schoolgroups. I am having trouble writing an online form_for button that a user can click on to apply to the school. The params I need to be included in the creation of the schoolgroup object are the user_id, the school_id, and the role 'applicant'. I know that I can use current_user.schoolgroups.build to have the form initialize a create action and include the correct user_id, but the problem I am having is how to write a form which sends the school_id to the controller to create the new schoolgroup object. The #school instance variables in my code are just placeholders for whatever the correct code should be
def create
#school = School.find(params[:schoolgroups][:school_id)
current_user.schoolgroups.build(school_id: #school.id, user_id: current_user.id, role: 'applicant')
respond_with school_path
end
<%= form_for( current_user.schoolgroups.build(params[school_id: #school.id]),
remote: true) do |f| %>
<div><%= f.hidden_field :school_id %></div>
<%= f.submit "Apply", class: "btn btn-large btn-primary" %>
<% end %>
I'd go this way
# in routes
resources :schools do
member do
put :apply
end
end
# in schools_controller.rb
def apply
#school = School.find(params[:id])
#schoolgroup = current_user.schoolgroups.create(school: #school, role: 'applicant')
respond_with #schoolgroup
end
#in your view
<%= link_to "Apply", apply_school_path(#the_school_var_you_define_somewhere), remote: true, method: :put,
class: "btn btn-large btn-primary" %>
This is simplier, and more in the Rails spirit.

Resources