Rails: saving a user field from another controller - ruby-on-rails

Combo: Rails4, Mongoid
I have an Admin console dashboard: /admin/moderator-slug/dashboard
that lists all users with a button to go manage that user:
<%= link_to "Manage", { controller: 'admin', action: 'manage', user: user} %>
As you can see, I pass that user in the params.
In my Admin controller, my manage action is as follows:
def manage
#user = User.find(params[:user])
if params[:follow_up].present?
#user.follow_up = Date.strptime(params[:follow_up], "%m/%d/%Y")
end
end
It successfully leads to the management page: /admin/moderator-slug/manage?user=managed-user-slug and finds the #user through the params I pass with the button.
In my User model I created a Time field "follow_up".
I want to update that field with a certain time selected with datepicker, so I created the following form_tag:
<%= form_tag manage_path, method: "get", remote: true do %>
Follow up: <%= text_field_tag "follow_up", nil, autocomplete: "off" %>
<%= submit_tag "Create" %>
<% end %>
When I press the submit button I get Mongoid::Errors::InvalidFind
When I pass on a hidden field <%= hidden_field_tag :user , #user %> , I get 404. And besides, I have a feeling my set up is not the healthiest, so passing on that hidden field is really a workaround that could be avoided.
my routes:
authenticate :user, -> (u) { u.is_moderator? } do
match 'admin/:slug/dashboard', to: 'admin/admin#dashboard', via: 'get', as: :dashboard
match 'admin/:slug/manage', to: 'admin/admin#manage', via: 'get', as: :manage
end
Any suggestions?

Looks like you should add user slug to your form URL:
<%= form_tag manage_path(user: #user), method: "get", remote: true do %>

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.

Rails 5: Two search form_tags on the same page

I'm trying to implement a two search form_tag on a the same page, each search form is placed inside dynamic bootstrap tabs. The first one which is working is basic a search form with one field. The second one which is not working has two fields, one is the same search method as the first and the other I'm trying to get the address from the other_location field and via params[:other_location].
With the current setup the other_location field form the second form does not appear!
Both of the forms are inside partials and I am rendering them inside two dynamic bootstrap tabs like this:
<%= render 'pages/search' %>
<%= render 'pages/search_other' %>
<%= form_tag search_items_path, :method => "get" do %>
<%= text_field_tag :search, params[:search], autofocus: true,
class: "search-query search_size",
placeholder: "Enter product to search" %>
<%= submit_tag "Search", name: nil, :style => "display: none;" %>
<%end%>
<%= form_for :search_other_path, :method => "get" do |form| %>
<%= form.text_field :search, autofocus: true,
class: "search-query search_size",
placeholder: "Enter keyword to search" %>
<% form.fields_for :other_location_path, :method => "get" do |f| %>
<%= f.text_field :other_location, class: "search-query search_size",
placeholder: "Enter address to search" %>
<%= form.submit "Search", name: nil, :style => "display: none;" %>
<%end%>
<%end%>
model
def self.search(search)
return where("0=1") if search !~ /\w{4}/
where("lower(title) LIKE lower(:term)", term: "%#{search}%")
end
routes.rb
get 'search' => 'pages#search', as: 'search_posts'
get 'search' => 'pages#search_other', as: 'search_other'
get 'search' => 'pages#other_location', as: 'other_location'
controller:
def search_other
if params[:search]
#posts = Post.near(other_location,10).search(params[:search]).page(params[:page])
else
#posts = []
end
end
def other_location
other_location = params[:other_location]
if params[:other_location]
Geocoder.search(params[:other_location])
end
end
def search
if params[:search]
#posts = Post.near(action,10).search(params[:search]).page(params[:page])
else
#posts = []
end
end
On your route file:
get 'search/other' => 'pages#search_other', as: 'search_other'
get 'search' => 'pages#search_other', as: 'search_other_items'
both GET requests are going to your pages_controller.rb #search_other method. So even if you have the two form_tags sending the data to different paths (search_other_path, and search_other_items_path) it would be going to the same controler method - which is redundant.
On your actual HTML you have two form tags:
<%= form_tag search_items_path, :method => "get" do %>
and
<%= form_tag search_other_items_path, :method => "get" do %>
You have not mentioned search_items_path in your routes, so I have no idea where that's pointing to. Likely its a proper controller that works since you mentioned the first form was the only one working.
Now, your mentioned controller only has a search method. So to start you are looking at the wrong controller. You should be looking at the controller methods being referenced by the form's action.
In this case, the second form is sending it's request to search_other_items_path which according to your routes, its pointing to pages_controller.rb -> #search_other method.
You should edit your question to include code that is actually relevant. Maybe then I can actually help.

Updating a rails attribute through a model association

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

How do I validate text_field_tag used for searching purpose in rails 4.1

In homepage/index:
<%= form_tag :controller => 'hotels', :method => 'get' do %>
<%= text_field_tag :search, nil, :class => 'search-box'%>
<%= submit_tag "Search", :name=>'btnsearch' %>
<%end%>
In hotels_controller:
def index
#hotels= Hotel.where('hotel_location LIKE ?',"%#{params[:search]}%")
I am new to Rails and I am wondering that how to validate text_field_tag for nil value.Means if no record was found, then display the error message without redirecting to the hotel/index page.
Your question is somewhat paradoxial:
If no record was found, then display the error message without
redirecting to the hotel/index page
What you're asking is to perform the functionality which can only be achieved after you've sent a request to your app, and then display the message without redirecting?
Ajax
You'll probably be best using Ajax (Asynchronous Javascript and XML):
This is a way of sending & receiving requests outside the scope of the typical "HTTP" request (IE without reloading the page). This sounds like what you're looking for, as it will ensure you're able to return the data you want without redirecting to your index view again.
The importance of Ajax is that it provides many HTTP developers with the ability to create much more "organic" interaction structures within their applications (IE not having to reload the page every time you want to do something)
Ajax is very simple to implement - I'd recommend it for you:
--
Search
Here's what I'd do:
#app/assets/javascripts/application.js
$(document).on("ajax:success", "#search", function(status, data, xhr){
$(this).append(data);
});
#config/routes.rb
...
resources :hotels do
get :search, on: :collection
end
#app/views/homepage/index.html.erb
<%= form_tag hotels_search_path, method: :get, id: "search", remote: true do %>
<%= text_field_tag :search, nil, :class => 'search-box'%>
<%= submit_tag "Search", :name=>'btnsearch' %>
<% end %>
This will send a "get" request to your hotels_search path - which will allow you to do the following:
#app/models/hotel.rb
class Hotel < ActiveRecord::Base
def self.search search
results = where('hotel_location LIKE ?',"%#{search}%") if search
if results
return results
else
return "No Records"
end
end
end
#app/controllers/hotels_controller.rb
class HotelsController < ApplicationController
respond_to :js, :json, :html
def search
#hotels = Hotel.search params[:search]
respond_with #hotels, layout: false
end
end
how to validate text_field_tag for nil. if no record was found, then display the error message without redirecting to the hotel/index page.
Looks like you need to validate it on client side. You can checkout bootstrap validator which is really nice for using validations on client side.
If you want to write your own js to handle it then you can do something like this:
$(document).on("click","#your_btn_id",function(e){
var textValue = $(this).closest(".search-box").val();
if(textValue == ""){
e.preventDefault();
alert("Please enter some value");
}
});
Update:
You can also utilize HTML5 validations and won't need any js
<%= form_tag :controller => 'hotels', :method => 'get', :validate=>true do %>
<%= text_field_tag :search, nil, :class => 'search-box', :required => true %>
<%= submit_tag "Search", :name=>'btnsearch' %>
<%end%>
If you don't want to use ajax then you can do:
def index
#hotels= Hotel.where('hotel_location LIKE ?',"%#{params[:search]}%")
if #hotels
#your action
else
flash[:notice] = "Please enter a valid value"
render 'your_form_action'
end
end
Since Rails generates HTML5, I am sure you can leverage its required attribute to have Search text box as a mandatory field on your view page. Like this:
<%= form_tag :controller => 'hotels', :method => 'get' do %>
<%= text_field_tag :search, nil, :class => 'search-box', :required => true %>
<%= submit_tag "Search", :name=>'btnsearch' %>
<%end%>
Just to be assured that your controller doesn't get nil in params[:search], you can change controller's index action with:
before_filter :validate_search, :only => [:index]
def index
#hotels = Hotel.where('hotel_location LIKE ?',"%#{params[:search]}%")
if #hotels.present?
# other operation here!
else
redirect_to :back # will work only when referrer is present!
rescue ActionController::RedirectBackError
redirect_to root_path
end
end
def validate_search
if params[:search].nil?
redirect_to root_path, notice: 'Enter few characters to search!'
end
end

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.

Resources