Rails Forms for custom actions - ruby-on-rails

I'm trying to link the input of a form to a specific action in my rails app.
Currently if I go to www.myapp.com/check/:idNumber, I'll be able to trigger the action just fine (which means routes is setup properly?). This action is basically a function call to a ruby/rails script with the parameter "idNumber" being passed to it. If the function is successful, it would return a newly created "Person" object and nil otherwise. This is different than the standard new operation as it determines the the attributes based on some information that it obtained from a database somewhere else.
Rake routes does give me the following:
check /check/:idNumber(.:format) person#check {:id=>/\d+/}
What I'm having trouble implementing is the form itself.
<%= form_tag("/check", :method => "get") do %>
<%= text_field_tag(:idNumber) %>
<% end %>
Controller action:
def check
regCheck = RegCheck.new
#person = regCheck.check_id(params[:idNumber])
if #person.name == nil
redirect_to root_path
end
end
submitting the form above would bring me to myapp.com/check?utf8=✓&idNumber=1234 instead. Can someone tell me what am I doing wrong?

I believe that using the check_path helper that is generated from the routes file is your best bet.
The form should look like this then.
<%= form_tag(check_path) do %>
<%= text_field_tag(:idNumber) %>
<% end %>

Rails forms can be finicky, especially when trying to build really customized forms.
This line
= form_for [#object]
Determines where the form goes, as well as the object that is being implemented. If you want to route the form to a different place, you can user the :url option. This options determines the path of the form, however you must keep in mind that the method is determined by the #object. If it is a new object, the method will be POST, an existing object will use a PUT method.
Let's suppose you want to update an existing object, but you want to send in data for a new object belonging to the existing object. That would look like
= form_for [#object], :as => #child_object, :url => my_optional_custom_path do |f|
# etc...
This generates a form sending a PUT request to the custom url (or the update path for #object if no custom url is supplied. The PUT request is sent with the parameter params[:child_object].
Hopefully this helps!
Best,
-Brian

I don't think it's possible the way you're trying.. The URL for the form is created before the user inputs any data.. So you need to remove the :idNumber from your routing..
If you do you get the following route:
check /check(.:format) person#check
Because the regex is removed now, you need to do this in you're controller:
def check
# Make sure ID is digits only
idNumber = params[:idNumber].gsub(/[^\d]/, '')
regCheck = RegCheck.new
#person = regCheck.check_id(idNumber)
if #person.name == nil
redirect_to root_path
end
end
You're form is allright, but you may want to use check_path like TheBinaryhood suggests..
If you really want it to be check/:idNumber you may also be able to submit the form to another action and redirect it to the right path from there..

Related

undefined method `pushes_path' for #<#<Class:0x007f85a15c6c90>

i'v been trying to resolve this error for the past 5 hours and I'm gonna burn my computer if I can't solve this.
undefined method `pushes_path' for #<#:0x007f859d605250> this is the error code I'm getting but i don't understand why.
this is my index.html.erb file inside of the interaction
<%= simple_form_for #push do |f| %>
<%= f.input :payload, as: :text %>
<%= f.input :segment, as: :radio_buttons %>
<%= submit_tag "start the campaign" %>
<% end %>
and this is my interaction controller
class InteractionController < ApplicationController
def index
#push =Push.new
end
end
Push is my table in the database and i'll get the inputs and write them in the database to use them for later one.
and this is my routes file
devise_for :partners
get 'home/index'
get 'segmentation/index'
get 'interaction/index'
root to: "home#index"
i really don't know why its looking for pushes_path, what am i doing wrong?
form_for
The problem you have is that your form_for method is going to try and generate a route based off your #path object. And as such, if you don't have a path created for it, you'll receive the error you're getting:
:url- The URL the form is to be submitted to. This may be represented
in the same way as values passed to url_for or link_to. So for example
you may use a named route directly. When the model is represented by a
string or symbol, as in the example above, if the :url option is not
specified, by default the form will be sent back to the current url
(We will describe below an alternative resource-oriented usage of
form_for in which the URL does not need to be specified explicitly).
The bottom line is that as Rails is object orientated, its built around the assumption that you'll have routes set up to handle the creation of individual objects.
Every time you use form_for, Rails will attempt to construct your routes from your object -- so if you're trying to do the following, it will treat the routes as photo_path etc:
#app/views/pushes/new.html.erb
<%= form_for #push do |f| %>
...
<% end %>
--
Fixes
As #mandeep suggested, there are several fixes you can employ to get this to work:
Firstly, you can just create a route for your push objects:
#config/routes.rb
resources :pushes
Secondly, as you're using a different controller, you'll want to do the following:
#config/routes.rb
resources :interactions
#app/views/pushes/new.html.erb
<%= form_for #push, url: interaction_path do |f| %>
...
<% end %>
This will route your form submission to the interactions controller, rather than the pushes controller that you'll get by default!
Objects
Something to consider when creating Rails-based backends is the object-orientated nature of the framework.
By virtue of being built on Ruby, Rails is centered on objects - a term for a variable, which basically encompasses much more than just a piece of data. Objects, in the case of Rails, are designed to give the application:
Once you understand this, the entire spectrum of Rails functionality becomes apparent. The trick is to realize that everything you do in Rails should be tied to an object. This goes for the controllers too:
--
Ever wondered why you call resources directive in your routes, for a controller? It's because you're creating a set of resourceful routes based for it:
Do you see how it's all object orientated?
This gives you the ability to define the routes for specific controllers etc. The most important thing to note is how this will give you the ability to determine which routes / controller actions your requests should go
--
There's nothing wrong in using the controller setup as you have - the most important thing is to ensure you're able to define the custom URL argument, as to accommodate the non-object based structure
In your index action you have
def index
#push =Push.new
end
and your form has
<%= simple_form_for #push do |f| %>
so your form is looking for /pushes with post verb or pushes_path and you don't have that route in your routes.rb file so to fix this you need to add this in routes.rb:
resources :pushes
Update:
when you add resources :push rails basically creates seven different routes for you. One of which is
POST /pushes pushes#create create a new push
and if you look at the html generated by your form it would be something like:
<form action="/pushes" class="new_push" id="new_push" method="post">
// your fields
</form>
notice the action and verb so when you submit your form your routes are checked for them and since you didn't define them in your routes you were getting this error
And how will i be able to use the params i m getting from this form with this new resource addition?
Your form will take you to pushes_controller create action so first of all you'll have to define them. You can access them simply by params[:pushes] in your controller action but since you want to create a new record so you'll have to permit those attributes, checkout strong parameters
If you are using rails >= 4 then you can do
class PushesController < ApplicationController
def create
#push =Push.new(push_params)
if #push.save
redirect_to #push
else
render 'interaction/index'
end
end
private
def push_params
params.require(:push).permit(:attributes)
end
end
If you are using rails < 4 then instead of permitting these attributes(because strong parameters feature came from rails 4) you'll have to tell rails that these attributes are accessible by writing this in your pushes.rb
attr_accessible :attribute_name
Why it is assuming that its pushes controller?Because of the Push.new creation?
That's because if you look at your index action #push = Push.new so #push contains a push object with nil values(as you have just initialized it) so this is where rails magic comes, rails automatically tries to figure out url of your form and since your #push is only an initialized variable so rails takes you to create action for it. For details you should checkout rails polymorphic urls If you want your form to go to interaction_controller or some other url then you'll have to specify the url option for it
<%= form_for #push, url: "your_url_for_custom_method" %>
// other fields
<% end %>
And in the end you should really read docs

Manage Single Rails form to other controller with create and update action

i'm new of rails. I use rails 3.0.5 .
I have an EMPLOYEE resource, but I would like to manage it with another extern controller (emp_profile_controller).
This extern controller (emp_profile_controller) manages some actions (index, new_employee, create_employee, edit_employee, update_employee ecc.. ) .
My routes for this controller are :
controller :emp_profile do
get 'emp_profile' => :index
get 'emp_edit_profile' => :edit_employee
put 'emp_edit_profile' => :update_employee
get 'new_employee' => :new_employee
post 'new_employee' => :create_employee
get 'emp_list' => :emp_list
end
How can i use one form to handle both Create and Update actions in this controller ?
I tried with :
form_for(#employee, :url => { :controller => "emp_profile"}) do |f|
but it doesn't work.
If i manage only one action at time (create OR update), url_for works, for example :
form_for(#employee, :url => { :controller => "emp_profile", :action => "update_employee" }
but how can i handle both actions with one form ?
Thanks for your availability and I apologize if I asked a stupid question.
EDIT
For now, i solved checking if object exist in the form file, if exist i set a variable with the UPDATE action path, else, i set a variable with the CREATE action path. So in the form_for statement i use url_for with the above variable.
<% if #employee.new_record?
action = "create_employee"
method = "post"
else
action = "update_employee"
method = "put"
end
%>
form_for(#employee, :url => { :controller => "emp_profile", :action => action }, :method => method
I don't think it is the best way but it works and i can use only one form file.
As your model name and controller name are different, you can add this line to your routes
resources :employees,:controller=>"emp_profile",:path=>"emp_profile"
Change the method names of create_employee,update_employee to create and update respectively.
And change your form_for as given below
<%= form_for #employee do |f| %>
....
<% end %>
First of all, if you want to update something, this object should exist.
How do plan to find it out, I don't know (cause there different ways, depends on background).
There are 2 ways of solving this issue.
You can just check if object exist in view file, and if exists, renfer form for update, else for create.
Other way is to do it in controller.
For example:
def create
#employee=Employee.find_by_name('Jack Black') #for example
if #employee!=nil
render :action=> 'update'
else
#employee=Employee.new(:employee)
#employee.save
end
as i understand you want to execute two different actions on the same controller using a form submitting, this is not possible, you can only execute one action using a form submitting,
because the form is reaching to an action controller that action is suppose to render some view at the end of it's execution code, if it was possible to use to actions on form submitting how rails will know which view to render??? (that's why it's not possible).
if you want to do some more code execution at the controller, the right way to it is to call a method with some code in it that you want to execute, that method should be in the model,
because it is a good practice to write all massive chunks of code in the model and leave the controller as light from code as possible :-)
hope this helps.

Newbie rails database relation question

I have two models Station and Broadcast. Broadcast belongs_to Station and has a station_id column.
I don't know how to make new method in BroadcastController to expect the station_id value and how to create a new Broadcast with right station_id in it.
I'd recommend against using a link_to here. Using a 'get' action to change/add data on the server is generally frowned upon. Also, I wouldn't use the 'new' action, as it's used by convention in a Rails Restful route to present a form, not actually persist data. All that said, the simple answer to your question is to pass a value through the link_to helper like so:
link_to 'Add broadcast', new_broadcast_path(:station_id => station.id)
...and your 'new' method on BroadcastsController would do:
def new
#broadcast = BroadCast.new(:station_id => params[:station_id])
if #broadcast.save
flash[:notice] = "New broadcast created!"
redirect :back # or whatever
else
# etc.
end
end
But, again, this is not the right way to do this. What you probably want to do is stay within the Rails (and web) conventions and use a form to create the new broadcast record by way of the 'create' action on the controller. You might place this form next to your stations on the index view which presents a button that points to the correct 'create' action of BroadcastsController, and uses a hidden_field to set the station_id. Something like (EDIT: better use of hidden_field):
<% form_for :broadcast do |f| %>
<%= f.hidden_field :station_id, :value=> station.id %>
<%= submit_tag 'Add broadcast' %>
<% end %>
Assuming you've set a restful route in routes.rb for broadcast like:
map.resources :broadcasts
...then your form will automatically point to a 'create' action on BroadcastsController, which you should write to look something like:
def create
#broadcast = BroadCast.new(params[:broadcast])
if #broadcast.save
# etc., etc.
end
The Rails Guides are a good place to get more comfortable with the Rails controller actions. I'd also spend some time looking over the RESTful actions and how they're used in Rails as well.
You actually do specify a station_id for your Broadcast model, such as
script/generate scaffold broadcast name:string station_id:integer ...
so when you add a broadcast record, it will ask you for a station_id.

Ruby On Rails: using arrays with link_to

I was curious on how to use arrays in the link_to method in ruby on rails for example:
Controller:
def index
#test = [1,2,3]
end
View:
<%= link_to "test", {:action => 'index'}, :test => #test %>
When looking at the source then, I end up with something to the effect of:
test
My guess is that the array's to_string or something similar is getting called to set the value of test in the html.
My goal is to be able to have a form in which people can submit data on the page, and then once they've submitted the data and return to the page, if they click on the link the data will persist through clicking on the link.
*Ideally I would like to do this without having to pass the parameters in the url.
Thank you.
If you want to keep data you should probably use cookies. They are very easy to use, just assign a value with the following in the action:
cookies[:some_key] = "some value"
and retrieve it with this:
cookies[:some_key] # returns "some value"
However, just to clarify what link_to is doing in your example:
<%= link_to "test", {:action => 'index'}, :test => #test %>
When looking at the source then, I end up with something to the effect of:
test
The reason is that you are passing #test to the third argument in link_to, which is a hash of html attributes, hence why it's turned into one. To have it become an parameter on the link, you need to pass it with the second, eg, {:action => 'index', :text => #test}. As noted above, however, this is not necessarily the best way to tackle this and, in addition, it's usually best to also pass the controller name to link_to or, better yet, use a named route.
If I understand well, you want to keep the datas submitted by the user after they validate the form ?
Well Rails is able to do that without any of your code line needed.
Based on the supposition that you have a route resource "objects"
In your controller :
def edit
#object = Object.find_by_id params[:id]
end
def update
#object = Object.find_by_id params[:id]
if #object.update_attributes params[:object]
# The datas have been successfully saved. You redirect wherever you want to.
else
render :action => 'edit'
end
end
and in your view :
<% form_for #object do |f| %>
<%= text_field :name %>
<% end %>
When the form fails to validate, the "name" text field automatically gets the previous entered data.
If after that you still need to reload your datas, you don't need to add them as a parameter in a link tag.
You get the object in your controller and passes it's datas to the view where you display it.
I would just write a view helper that formats it into a string with good separators, like commas.
That isn't a good way to be passing along information though. Try session variables, cookies, or url-encoded variables instead.
The best match to what you are doing would be url-encoded variables, which will show up in a form similar to this:
test
My guess is that it is using Array#join.
You could try something like
:test => #test.join( ',' )
and then parse the string in your controller. But it is somewhat error prone if the user enters the same character you chose as delimiter.
But, assuming the linked page is also served by Rails, I think the best solution would be to use the flash area to store the results on the server
flash[ :submitted_params ] = params;
and in the controller for the linked page
old_params = flash[ :submitted_params ] || {}

Rails - link_to, routes and nested resources

As my understanding on nested resources, on edge Rails, should not
link_to 'User posts', #user.posts
point to
/users/:id/posts
?
The routes.rb file contains
map.resources :users, :has_many => :posts
If this is not the default behavior, can it be accomplished doing something else?
Along the same lines as Rishav:
link_to "User Posts", [#user, :posts]
Here's an explanation from my blog.
Really early on in Rails, you would write routes like this:
redirect_to :controller => "posts", :action => "show", :id => #post.id
What this would do is dutifully redirect to the show action inside the PostsController and pass along the id parameter with a
value of whatever #post.id returns. Typical 302 response.
Then Rails 1.2 came along and allowed you to use routing helpers, like this:
redirect_to post_path(#post)
And the people rejoiced.
This would do effectively the same thing. post_path here would build a route using the #post object that would look something
like /posts/1 and then redirect_to would send back a 302 response to that route and the browser would follow it.
Then later versions (I can't remember which one), allowed syntax like this:
redirect_to #post
And the people rejoiced a second time.
Magic, but not really
Any sufficiently advanced technology is indistinguishable from magic.
While this seems like magic, it's not. What this is doing is actually very, very neat. The redirect_to method, much like its cousins link_to and form_for all use a common method to build URLs, called url_for. The url_for method takes many different
varieties of objects, such as strings, hashes or even instances of models, like in the example above.
What it does with these objects then, is quite neat. In the case of the redirect_to #post call above, it inspects the #post
object, sees that it is an object of the Post class (we assume, anyway) and checks to see if that object has been persisted in a
database somewhere by calling persisted? on it.
By "persisted", I mean that a Ruby object has a matching record in the database somewhere. The persisted? method in Active Record is implemented like this:
def persisted?
!(new_record? || destroyed?)
end
If the object wasn't created through a call such as Model.new then it won't be a new record, and if it hasn't had the destroy method called on it won't be
destroyed either. If both of these cases are true, then that makes the object has most likely been persisted to the database in the form of a record.
If it has been persisted, then url_for knows that this object can be found
somewhere, and that the place it can be found is most likely under a method called post_path. So it calls this method, and passes
in the to_param value of this object which is usually the id.
In short, it's effectively doing this:
#{#post.class.downcase}_path(#post.to_param)
Which comes out to being this:
post_path(1)
And when that method is called you would get this little string:
"/posts/1"
Lovely!
This is called polymorphic routing. You can pass an object to methods like redirect_to, link_to and form_for and it will
attempt to work out the correct URL of what to use.
The form of form_for
Now, when you're coding Rails you may have used form_for like this a very long time ago:
<% form_for #post, :url => { :controller => "posts", :action => "create" } do |f| %>
Of course, with advancements in Rails you could simplify it to this:
<% form_for #post, :url => posts_path do |f| %>
Because the form is going to default to having a POST HTTP method and therefore a request to posts_path is going to go to the
create action of PostsController, rather than the index action, which is what would result if it were a GET request.
But why stop there? Why not just write this?
<%= form_for #post do |f| %>
Personally, I see no reason not to... if it's something as simple as this. The form_for method uses url_for underneath, just like
redirect_to to work out where the form should go. It knows that the #post object is of the Post class (again, we assume) and it
checks to see if the object is persisted. If it is, then it will use post_path(#post). If it's not, then posts_path.
The form_for method itself checks to see if the object passed in is persisted also, and if it is then it'll default to a PUT HTTP
method, otherwise a POST.
So this is how form_for can be flexible enough to have an identical syntax on both a new and edit view. It's becoming more and
more common these days for people to even put their whole form_for tags into a single partial and include it in both the new and
edit pages.
A more complex form
So form_for is fairly simple for when you pass a normal object, but what happens if you pass an array of objects? Like this, for
instance:
<%= form_for [#post, #comment] do |f| %>
Well, both url_for and form_for have you covered there too.
The url_for method detects that this is an array and separates out each part and inspects them individually. First, what is this
#post thing? Well, in this case let's assume it's a Post instance that is persisted and has the id of 1. Second, what is this
#comment object? It's a Comment instance that has not yet been persisted to the database.
What url_for will do here is build up the URL helper method piece by piece by placing each part in an array, joining it into a routing method and then calling that routing method with the necessary arguments.
First, it knows that the #post object is of the Post class and is persisted, therefore the URL helper will begin with post. Second, it knows that the #comment object is of the Comment class and is not persisted, and therefore comments will follow post in the URL helper build. The parts that url_for now knows about are [:post, :comments].
The url_for method combines these individual parts with an underscore, so that it becomes post_comments and then appends _path
to the end of that, resulting in post_comments_path. Then it passes in just the persisted objects to the call to that method, resulting in a call like this:
post_comments_path(#post)
Calling that method results in this:
"/posts/1/comments"
Best part? form_for will still know to use POST if the #comment object is not a persisted object, and PUT if it is. A good
thing to remember is that the form_for is always for the last object specified in the array. The objects prior to it are just its
nesting, nothing more.
The more objects that are added, the more times url_for will do the hard yards and build the path out... although I recommend that
you keep it to just two parts.
A symbolic form
Now that we've covered using an array containing objects for form_for, let's take a look at another common use. An array containing
at least one Symbol object, like this:
<%= form_for [:admin, #post, #comment] do |f| %>
What the url_for method does here is very simple. It sees that there's a Symbol and takes it as it is. The first part of the
url will simply be the same as the symbol: admin. The URL that url_for knows of at this point is just [:admin].
Then url_for goes through the remaining parts of the array. In this case, let's assume both #post and #comment are persisted
and that they have the ids of 1 and 2 respectively. Same classes as before. url_for then adds post to the URL that it's building,
and comment too, resulting in [:admin, :post, :comment].
Then the joining happens, resulting in a method of admin_post_comment_path, and because both #post and #comment are persisted here,
they're passed in, resulting in this method call:
admin_post_comment_path(#post, #comment)
Which (usually) turns into this path:
/admin/posts/1/comments/2
You can use the array form of polymorphic routing with the redirect_to, link_to and form_for methods. There's probably other
methods that I'm not remembering right now that can do it too... it's generally anything in Rails that would normally take a URL.
There's no need to build your URLs in any Rails version greater-than 2 using hashes; that's pretty old school.
Instead, experiment with your new knowledge of polymorphic routing and use it to the best of your advantage.
This should work:
link_to "User Posts", user_posts_path(#user)
for more details visit:
http://guides.rubyonrails.org/routing.html
link_to uses url_for which uses polymorphic_url.
polymorphic_url:
builds the helper method, using the class name of active record objects
calls the helper with the active record objects as arguments
Therefore, as others said, you should use:
link_to 'User Posts', [#user, :posts]
for which the path is:
user_posts_path(#user)
^^^^ ^^^^^ ^^^^^
1 2 3
class of #user because it is an active record
convert to string because symbol
add as call argument because active record
That builds the good helper method.
This is how to link to a nested resource in the latest Rails:
link_to 'Destroy Comment', post_comment_path(comment.post, comment)
Note: This is in a partial so there isn't a #.

Resources