Submit form through GET requets


#1

I’m trying to create a form that a user can submit data into through the
URL, using a get request. That is, they would go to something like
http://localhost:3000/links/new?url=http://www.google.com and
http://www.google.com would be submitted.

Right now my controller looks like:

<% form_for @link, :method => :get do |f| %>
<%= f.error_messages %>

<%= f.label :url %>
<%= f.text_field :url %>

<%= f.submit 'Create' %>

<% end %>

Currently, going to that address doesn’t do anything in the browser and
this gets output in the terminal: “Processing LinksController#new (for
127.0.0.1 at 2009-04-25 11:36:26) [GET]
Parameters: {“url”=>“http://www.google.com”}”

Putting “http://www.google.com” in the actual textfield and hitting the
submit button gets this output: " Parameters: {“commit”=>“Create”,
“authenticity_token”=>“nii2AAhoBYGSYW3ggw1Ul8ENZJLMRR6mJg2AfBWdloQ=”,
“link”=>{“url”=>“http://www.google.com”}}".

Can anyone let me know what I’m doing wrong? Thanks in advance.


#2

Cisco Ri wrote:

Right now my controller looks like:

<% form_for @link, :method => :get do |f| %>

  1. Controller? Isn’t that a View?

  2. Looking at an example in my book for form_for shows that the first
    argument for form_for is a Symbol, e.g. :link.

  3. You didn’t specify the action(a method in the controller) that you
    want the form data to get sent to, for instance:

<% form_for :link,
:url => {:action => :new} … %>

Since a rails url is of the form:

host/controller/action

and your url is:

http://localhost:3000/links/new?url=http://www.google.com

you are trying to call an action(or method) named new that is defined in
the links controller. That is why I specified :new for the action.

  1. My book shows specifying the :method a different way:

<% form_for :link,
:url => {:action => new},
:html => {:method => :get} … %>

  1. Did you define a method called new in the controller whose view this
    is?

I don’t know if some of those changes are because I’m using rails 2.3.2
and you are using a 1.x version or not. I would guess that it’s
mandatory to state what version of rails you are using when you post a
rails question.


#3

Rails 2.3.2. Yeah, I meant that is the view. The relevant actions in
the controller are:

GET /links/new

GET /links/new.xml

def new
@link = Link.new

respond_to do |format|
  format.html # new.html.erb
  format.xml  { render :xml => @link }
end

end

POST /links

POST /links.xml

def create
@link = Link.new(params[:link])
@link = current_user.links.build(params[:link])
@link.title = WWW::Mechanize.new.get(@link.url).title
respond_to do |format|
if @link.save
flash[:notice] = ‘Link was successfully created.’
format.html { redirect_to(@link) }
format.xml { render :xml => @link, :status => :created,
:location => @link }
else
format.html { render :action => “new” }
format.xml { render :xml => @link.errors, :status =>
:unprocessable_entity }
end
end
end


#4

When I use <% form_for :link,
:url => {:action => :new},
:html => {:method => :get} do |f| %>

the type http://www.gmail.com into the form and hit submit, the address
bar changes to
http://localhost:3000/links/new?link[notspamurl]=http%3A%2F%2Fwww.gmail.com&commit=Create
(remove notspam) and nothing gets added to the database.


#5

7stud – wrote:

Link.create(“url” => params[:url])

(that assumes the links table has only one field: url)

Apparently when you assign a Link object to the variable @link, rails
will create a record in the database corresponding to the values in the
Link object. If you look at the create method in the file
LinksController.rb, that is what the create method does. This is what I
came up with:

@link = Link.create(“url” => params[:url])

After some more testing, I discovered that you don’t have to assign the
Link object to @link. I think that when you create a Model object(e.g.
a Link object) and the Model is hooked up to a database, then as soon as
you create the object, rails inserts a record corresponding to that
object in the table.


#6

Cisco Ri wrote:

When I use <% form_for :link,
:url => {:action => :new},
:html => {:method => :get} do |f| %>

the type http://www.gmail.com into the form and hit submit, the address
bar changes to
http://localhost:3000/links/new?link[notspamurl]=http%3A%2F%2Fwww.gmail.com&commit=Create
(remove notspam) and nothing gets added to the database.

Sorry, I just started with rails, and modifying the scaffold generated
files like you did seems to interfere with the complex web of
relationships. Also, any attempt I made to call one of the methods in
the LinksController directly, e.g.

http://localhost:3000/links/create

gave me a routing error. That is probably for security reasons.

Because you don’t care about the form page, why not bypass it
altogether? The form page is for gathering the data from the user and
assembling it into a url and then calling the url. Your user is going
to assemble the url themselves and call the url by themselves–by
entering the url in their browser’s address bar. So you can tell the
user to assemble a url that calls one of your own methods(=an action),
which then enters the link in the links table.

Here’s something that worked for me:

  1. Create a new controller and action that the user will enter as the
    url:

$ ruby script/generate controller direct entry

That creates a controller called DirectController with one action(=a
method) called entry. Open up app/controllers/direct_controller.rb and
you will see this:

class DirectController < ApplicationController
def entry
end

end

The name/value pairs in the url after the ? will be inserted into a
“params” hash, which you can access. With the information in params,
you can create a new Link object like this:

Link.create(“url” => params[:url])

(that assumes the links table has only one field: url)

Apparently when you assign a Link object to the variable @link, rails
will create a record in the database corresponding to the values in the
Link object. If you look at the create method in the file
LinksController.rb, that is what the create method does. This is what I
came up with:

@link = Link.create(“url” => params[:url])

Add that line to the entry method:

class DirectController < ApplicationController
def entry
@link = Link.create(“url” => params[:url])
end
end

Then when you enter the url:

http://localhost:3000/direct/entry?url=www.someurl.com

that will access the DirectController and call its entry method. The
entry method then creates a new Link object. Then rails enters a record
in the links table corresponding to the information in the Link object.

I have no idea whether that is the proper way to do things, and I can
see at least one issue: a GET request should not make any changes on the
host.


#7

7stud – wrote:

7stud – wrote:

7stud – wrote:

Link.create(“url” => params[:url])

(that assumes the links table has only one field: url)

Apparently when you assign a Link object to the variable @link, rails
will create a record in the database corresponding to the values in the
Link object. If you look at the create method in the file
LinksController.rb, that is what the create method does. This is what I
came up with:

@link = Link.create(“url” => params[:url])

After some more testing, I discovered that you don’t have to assign the
Link object to @link. I think that when you create a Model object(e.g.
a Link object) and the Model is hooked up to a database, then as soon as
you create the object, rails inserts a record corresponding to that
object in the table.

That isn’t quite right either. You have to save an object for rails to
enter it into a table:

mylink = Link.new
mylink.url = “www.somepage.com
mylink.save

However, rails provides a convenience method, create(), that both
instantiates a new object and inserts a record into the table. create()
takes a hash of name/value pairs as an argument, where each name is a
field in the table.

(Or, you can pass create() an array of hashes, where each hash
represents one record, and create() will insert multiple records at the
same time.)

I’m not sure that I follow you. Completely bypassing the form would be
nice.

I changed the new method to:
def new
@link = Link.create(“url” => params[:url])

respond_to do |format|
  format.html # new.html.erb
  format.xml  { render :xml => @link }
end

end

and it didn’t get written to the database. When I changed it to:

def new
@link = Link.new(“url” => params[:url])

respond_to do |format|
  format.html # new.html.erb
  format.xml  { render :xml => @link }
end

end

it goes to the form page with the correct URL in the textfield. This
was actually what I originally wanted, but it would be better to bypass
the form entirely.

Thanks for the help so far.


#8

7stud – wrote:

7stud – wrote:

Link.create(“url” => params[:url])

(that assumes the links table has only one field: url)

Apparently when you assign a Link object to the variable @link, rails
will create a record in the database corresponding to the values in the
Link object. If you look at the create method in the file
LinksController.rb, that is what the create method does. This is what I
came up with:

@link = Link.create(“url” => params[:url])

After some more testing, I discovered that you don’t have to assign the
Link object to @link. I think that when you create a Model object(e.g.
a Link object) and the Model is hooked up to a database, then as soon as
you create the object, rails inserts a record corresponding to that
object in the table.

That isn’t quite right either. You have to save an object for rails to
enter it into a table:

mylink = Link.new
mylink.url = “www.somepage.com
mylink.save

However, rails provides a convenience method, create(), that both
instantiates a new object and inserts a record into the table. create()
takes a hash of name/value pairs as an argument, where each name is a
field in the table.

(Or, you can pass create() an array of hashes, where each hash
represents one record, and create() will insert multiple records at the
same time.)


#9

Cisco Ri wrote:

Completely bypassing the form would be
nice.

Did you try this:

Here’s something that worked for me:

  1. Create a new controller and action that the user will enter as the
    url:

$ ruby script/generate controller direct entry

That creates a controller called DirectController with one action(=a
method) called entry. Open up app/controllers/direct_controller.rb and
you will see this:

class DirectController < ApplicationController
def entry
end

end

The name/value pairs in the url after the ? will be inserted into a
“params” hash, which you can access. With the information in params,
you can create a new Link object like this:

Link.create(“url” => params[:url])

(that assumes the links table has only one field: url)

Apparently when you assign a Link object to the variable @link, rails
will create a record in the database corresponding to the values in the
Link object. If you look at the create method in the file
LinksController.rb, that is what the create method does. This is what I
came up with:

@link = Link.create(“url” => params[:url])

Add that line to the entry method:

class DirectController < ApplicationController
def entry
@link = Link.create(“url” => params[:url])
end
end

Then when you enter the url:

http://localhost:3000/direct/entry?url=www.someurl.com

that will access the DirectController and call its entry method. The
entry method then creates a new Link object. Then rails enters a record
in the links table corresponding to the information in the Link object.


I’m not sure that I follow you.

If you create a Link object, then call .save on it, the information in
the Link object will be automatically inserted in the links table.
There are two ways to create and save a Link object:

  1. mylink = Link.new
    mylink.url = “some url”
    mylink.save

You create the Link object, then you set the field names–as found in
the links table–e.g. ‘url’, to the desired values.

  1. Link.create(info)

where info is a hash containing the information, e.g.:

{“field1” => val1, “field2” => val2}

In your case, I’m assuming your links table has one field named url, so
you could create a new record in the table by writing:

Link.create(“info” => “some url”)

An action is called with a url. The part after the ? in the url gets
entered into the rail’s params hash, which you can access inside the
action. For instance, if you enter the following url in your browser’s
address bar:

http://localhost:3000/direct/entry?url=www.someurl.com

that will call the entry method in the DirectController. Inside the
entry method, params[:url] will be equal to “www.someurl.com”. How
would you enter that url in the table? You can that url in the links
table by writing the following inside the entry method:

Link.create(“info” => params[:url])

or equivalently:

mylink = Link.new
mylink.url = params[:url]
mylink.save


#10

I’m going ahead with:

@link = @user.links.create!(“url” => params[:url])

I also changed my routes.rb file to include these lines:

map.resources :links

map.resources :users, :has_many => :links

It works, but I’m still having some trouble. With these lines

@link = @user.links.create!("url" => params[:url])
@link.title = title=(Hpricot(open(@link.url))/"title").inner_text

the action just repeats the URL as the title. Also, is there a way that
I can reuse the code from my create action:

def create
@user = current_user
@link = @user.links.create!(params[:link])
@link.title = title=(Hpricot(open(@link.url))/“title”).inner_text


#11

Cisco Ri wrote:

I’m going ahead with:

@link = @user.links.create!(“url” => params[:url])

I also changed my routes.rb file to include these lines:

map.resources :links

map.resources :users, :has_many => :links

It works, but I’m still having some trouble. With these lines

@link = @user.links.create!("url" => params[:url])
@link.title = title=(Hpricot(open(@link.url))/"title").inner_text

the action just repeats the URL as the title. Also, is there a way that
I can reuse the code from my create action:

def create
@user = current_user
@link = @user.links.create!(params[:link])
@link.title = title=(Hpricot(open(@link.url))/“title”).inner_text

Whoops, it actually doesn’t repeat the URL as the title – it works
correctly. But is there a way that I can reuse the code from the create
action?