I'm new to Ruby on Rails and I'm trying to update a device attribute (lastChangedBy) that will set its value to the user's IP address whenever the submit button is clicked. I wanted to do something like:
<%= form_for(#device) do |f| %>
.
.
.
<%= if click? ( f.submit "Commit Entries", class: "btn btn-primary" ) == true %>
<%= #device.lastChangedBy = request.remote_ip %>
<% end %>
but I don't think that's possible. I'm looking into using "button_to" but after searching online I am extremely confused to how to use it. I tried doing something like:
<%= button_to "Commit Entries", action: "setIp" %>
and then in DevicesController & in the helper.rb (because I wasn't sure where it would call the method) I made a simple method:
def setIp
Device.find(params[:id])
#device.lastChangedBy = request.remote_ip
end
but I am completely lost. Could someone please help me. It would be amazing if you were specific!
If you're already submitting a form, and want to set that parameter, do it in the controller:
class DevicesController < ApplicationController
def update
#device = Device.find(params[:id])
#device.last_changed_by = request.remote_ip # Tada!
if #device.update_attributes(params[:device])
redirect_to #device
else
render 'edit'
end
end
end
Tweak according to your application, but that's the basic idea.
Since you mentioned that you are unsure of how to utilize calling a function with button_to, and that you already have a method in your controller you can approach it as follows, by adding some fields to your view's button_to. With this approach you'll also be able to remove your form.
=button_to 'SetIp', {:controller => "your_controller",
:action => "setIp", :id => your_model.id}, {:method => :post }
And in your routes.rb
resources :your_controller do
post :setIp, :on => :collection
end
And in your_controller.rb
def setIp
device = Device.find(params[:id])
device.lastChangedBy = request.remote_ip
device.save!
#Can redirect to anywhere or render any page
redirect_to action: :index
end
Related
I'm working on a RoR backend for a big mobile app, currently with the admin panel.
I have two models: Activity and Deal, joined by HMT ActivitiesDeal. The join is tested both ways in rails console and works like a charm.
Activity is the model the app is built around, so admins need to be able to add deals to activity from the "Edit activity" form in some intuitive way.
I tried this for creating activities_deal:
<%=select("deal", #deal_id, Deal.all.collect {|d| [d.title, d.id]}, {})%>
<%= link_to "Add", link_activity_deal_path(activity_id: #activity.id, deal_id: #deal_id), method:'post' %>
But it doesn't work as I thought. Any ideas on how to send the correct deal_id to link_activity_deal_path? This seems like a problem that has been solved many times, but I can' find anything that fits.
ActivitiesDealsController:
class ActivitiesDealsController < ApplicationController
def create
#activity = Activity.find(params[:activity_id])
render file: 'public/404.html' and return unless #activity && Deal.find(params[:deal_id])
#activity_deal = ActivitiesDeal.new
#activity_deal.activity_id = params[:activity_id]
#activity_deal.deal_id = params[:deal_id]
if #activity_deal.save
redirect_to proc {activity_url #activity}
end
render file: 'public/500.html'
end
def destroy
p params
#activity = Activity.find(params[:activity_id])
render file: 'public/404.html' and return unless #activity
#activity_deal = ActivitiesDeal.where("activity_id == ? AND deal_id == ?", params[:activity_id], params[:deal_id])
render file: 'public/404.html' and return unless #activity_deal
ActivitiesDeal.destroy(#activity_deal)
redirect_to proc {activity_url #activity}
end
end
Fixed the problem by making a form_for outside of the edit page.
If anyone needs the code:
<%= form_for #activity, as: :deal, :url => link_activity_deal_path(activity_id: #activity.id), method:'post' do |f|%>
<%= f.collection_select :id, #deals, :id, :title %>
<%= f.submit "Add Deal", class: "btn btn-primary" %>
This is my first ror app.
I have main page: home.html.erb
I have form there.
<%= form_for(#lead ,:html => {:class => 'check_form'}) do |f| %>
<%= f.text_field :phone, placeholder: 'phone' %>
<%= f.submit "Check car status", class: "btn btn-large btn-primary" %>
<% end %>
Backstory: a customer(I call him Lead can input his phone number and check status of his car which is being repaired now.)
Right now this view home.html.erbis served by static_pages_controller
class StaticPagesController < ApplicationController
def home
#lead = Lead.new()
end
def help
end
def about
end
def contact
end
end
I have also LeadsController
class LeadsController < ApplicationController
*some code*
def create
#lead = Lead.new(lead_params)
if #lead.save
#sign_in #lead
flash[:success] = "Request successfully created!"
redirect_to #lead
else
render 'new'
end
end
* some code
end
What I want to do when user inputs his phone number to find lead in database with the same phone number and show repair status to user.
So back to my problem:
I know how to find lead by phone like this Lead.find(params[:id])
But where to write this code? I need to find lead by phone and then print it to screen. How can I do this?
What I want to do when user inputs his phone number to find lead in
database with the same phone number and show repair status to user.
Currently your form serves the wrong purpose. This requires a form with GET request. I'll be doing it by declaring a custom route like below
get :check_lead_car_status, to: 'static_pages#check_lead_car_status', as: 'check_lead_car_status'
And in the static_pages#check_lead_car_status
def check_lead_car_status
#lead = Lead.find_by(phone: params[:phone]
end
And modify the existing form like below
<%= form_tag check_lead_car_status_path, :method => :get do %>
<%= text_field_tag :phone, placeholder: 'phone' %>
<%= submit_tag "Check car status", class: "btn btn-large btn-primary" %>
<% end %>
And a page check_lead_car_status.html.erb with the below code
The Status of the Car is: <%= #lead.status %>
youre redirecting to #lead which means should be the show path in the lead controller. which means you need to put that logic in a method called show in your Lead controller
then in your view (views/leads/show.html.erb) you can access that variable
edit:
if all youre trying to do is query by a different parameter, then you should look into the active record query interface. specifically section 1.1.5
Lead.find_by(phone: params[:phone])
I have the following form and controller.
<%= form_tag do %>
<div>
<%= label_tag :Old %>
<%= password_field_tag :old_password %>
</div>
<div>
<%= label_tag :New %>
<%= password_field_tag :new_password %>
</div>
<div>
<%= label_tag :Confirm %>
<%= password_field_tag :confirm_password %>
</div>
<div>
<%= submit_tag "Update" %>
</div>
<% end %>
and the controller:
def change
#user = current_user
#op = params[:old_password]
#np = params[:new_password]
#cp = params[:confirm_password]
if #np == #cp
#user.update_with_password(:password => #np, :current_password=>#op)
if #user.save
flash[:notice] = "Password Successfully Changed"
redirect_to home_path
end
else
#user.errors.add("Incorrect confirmation")
end
end
This is all tied to 'password/change' in the config/routes.rb
The problem is that when I go to /password/change I immediately an redirected to home and receive the "password successfully changed" flash notice. What I take from it is that it is not requiring me to click the submit button in order to pass the parameters. How do I make it so that it waits for the submission of the form before continuing through the controller?
The problem is that you need 2 separate methods. One to show the view and one to handle the form post.
Right now the "change" method in your password_controller is handling the form post so you need a method like "index" to show the form
def index
#move your form to /views/password/index.html.erb or specifically render your 'change' view
end
Then in your markup add the action to your form
<%= form_tag('/password/change') do %>
…
Then in your controller you can specify POST only for the change method
class PasswordController < ApplicationController
verify :method => :post, :only => :change
…
UPDATE
Instead of using the verify method (removed in rails 3) you should either set up your route to be restful (Rails Routing from the Outside In) or you can create a specific route for changing the password like so:
match 'password/change' => 'password#change', :via => :post
The best practice will be to separate these two things into different controller methods. One should be used to simply display the view, while the other should be used to handle the POST request. However, if you're dead set on doing it this way, I believe a solution like this will work:
def change
#user = current_user
#op = params[:old_password]
#np = params[:new_password]
#cp = params[:confirm_password]
if #np && #np == #cp # This checks to see if params[:new_password] is nil
#user.update_with_password(:password => #np, :current_password=>#op)
I'd strongly suggest you separate it out though.
When you render password/change from the browser, params is nil, so #np == #cp always evaluates to TRUE, executes the update, saves, and does the redirect — in fact, if you check I would bet the user's password is being set to nil.
You need to make sure the params are not empty before attempting the update.
Does that help point you in the right direction?
side note: from a code readability standpoint I might recommend just using the variables inline, instead of the instance vars, but that's just my opinion :)
Something weird's happening with my Rails app. When I try to send an update command to one of my controllers, for some reason the submit button appears to be changing some of the params.
I'm using nested resources and setting up races which have participants. Pretty simple. For some reason, though, when I try to update a participant, it changes the value of :race_id to the participant's id (:id).
Though it only does that on update. I seem to be able to create new participants perfectly using the very same form, and so the very same submit button.
Here is some of the relevant code:
_form.rb (used by new and update)
<%= form_for ([:race, #participant]) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p><%= f.submit %></p>
<% end %>
participants_controller.rb
class ParticipantsController < ApplicationController
before_filter :authenticate_user!, :only => [:edit, :update, :destroy, :create, :new]
before_filter :set_up_race
...
def create
#participant = #race.participants.new(params[:participant])
if #participant.save
redirect_to setup_race_path(#race), :notice => "Successfully created participant."
else
render :action => 'new'
end
end
...
def update
#participant = Participant.find(params[:id])
if #participant.update_attributes(params[:participant])
redirect_to setup_race_path(#race), :notice => "Successfully updated participant."
else
render :action => 'edit'
end
end
...
def set_up_race
#race = Race.find(params[:race_id])
end
end
Here's why it seems that parameters are being changed:
If I modify the _form.rb file to include <%= params[:race_id] %>
The screen tells me 3
When I click submit I get:
Couldn't find Race with id=25
Request
Parameters:
{"utf8"=>"✓", "_method"=>"put",
"authenticity_token"=>"4VCZP9sI/iv8n454I8AE76n5vLiwGayuXc1NrPYfzGc=",
"participant"=>{"name"=>"hgdjhgf"}, "commit"=>"Update Participant",
"race_id"=>"25", "id"=>"25"}
(As you can see under parameters, "race_id"=>"25" after I click submit, but the page originally had :race_id =>"3" (proven above, and again if I do anything to make the form crash)).
So the question is, after all of that, why is :race_id changing somewhere between the view and the controller?
EDIT: here's a rake routes output, as per Jeff's request:
http://dylancodes.net/personal/ARTk/images/routes.png
What does the url look like that your form is posting to? Based on your routes, I would expect it to look something like /races/3/participants/25. From what I've read, the line
form_for ([:race, #participant]) do |f|
creates a namespaced route (search for "namespaced" on that page) that would look like /races/participants/25.
Does changing that line to this work for you?
form_for [#race, #particpant] do |f|
That should build the form url as /races/:race_id/participants/:id.
I decided to start a little project in rails 3 and I am a little bit stuck on a form... Where can I specified the f.submit action should go to a special controller / action ?
The code in the form is:
<%= form_for #user, :url => { :action => "login" } do |f| %>
<div class="field">
<%= f.text_field :email %><br />
<%= f.text_field :password %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
User is defined as #user = User.new in "index" method of "home_controller".
but I have the error:
No route matches {:controller=>"home", :action=>"login"}
as soon as I run http://0.0.0.0:3000
I am very sorry for this newbee question but I cannot find the routing details (I worked a little bit with rails a couple of years ago but...)
Thanks,
Luc
You don't need to specify any action for f.sumbit.
First of all, you need to make sure you put
resources :users
(for example)
in your routes.rb
then if you want to create a user
put
def new
#user = User.new
end
in your users_controller so you have a page to create new user
or you can put #user=User.new anywhere you like, remember to set
the route correctly
then
def create
#user = User.new(params[:id])
if #user.save
sign_in #user
redirect_to #user
else
render 'new'
end
end
is the part that does real work after you hit on submit
the actual part that connect your form with everything else is this line
<% form_for #user do |f| %>
you can change user to other object, and you can also edit form using update action in a controller.
Hope you got the idea
Whenever you use REST objects, the mere:
form_for #article
is enough for the form to find the proper path.
Otherwise, you can use helpers this way:
form_tag(:controller => "people", :action => "search", :method => "get", :class => "nifty_form")
More info here: http://edgeguides.rubyonrails.org/form_helpers.html