Part of the app i'm developing involves a form which has to create a product on the users shopify store and also create a row in my own database for an identical product (with a few extra bits of information).
Where i'm struggling is with the form itself, i can do this with a html based form, but i can't get a single ruby form to do both jobs. A shortened version of my controller create code is as follows;
def create
#item = Item.new
#item.item_title = params[:item_title]
#item.item_profit = params[:item_profit]
#new_product = ShopifyAPI::Product.new
#new_product.title = params[:item_title]
#new_product.save
#item.save
end
So as you can see i'm using the same params to set values for both the shopify product and the product in my own db. The HTML form looks like this:
<form action="/items/submit" >
<input type="text" name="item_title">
<br>
<input type="text" name="item_profit">
<br>
<br>
<input type="submit"/>
</form>
And it works fine, but how do i convert this into a ruby form that does the same job?
You can do like this:
form_tag('/items/submit')
text_field_tag 'item_title'
tag("br")
text_field_tag 'item_profit'
tag("br")
tag("br")
<%= submit_tag 'Save' %>
Instead of tag("br"), you can directly use < br />.
Related
How do I use some inputted text in a html form to query a SQLite database?
Forgive me, I am very new to Ruby on Rails (couple of days).
I am getting a user to enter a number followed by enter, I then want to query my SQLite db and return results to a variable. I am working in a Ruby on Rails project. Here is the code in my home.html.erb file.
<form name="myform" action="" method="get">
<input type="text" name="CardNumber" onkeypress="if(event.keyCode==13) {javascript:form.submit();>
<input type="submit" onClick="javascript:form.submit();"/>
<br>
</form>
<br>
<br>
<script type="text/javascript" language="JavaScript">
document.forms['myform'].elements['CardNumber'].focus();
</script>
First I think you'll want to do a post instead of a get. Then you need to point action to the correct route.
Usually in rails you'll have a model object instantiated on the action that renders the view with the form. Like if it's a form for creating a new User, on the controller#new action you'll have something like:
def new
#user = User.new
end
then on the view you'll have <%= form_for(#user) ... %>
Since you instantiated #user, form_for will be able to render correctly the path and action when you give it that object as a parameter. It won't be able to figure out if it's a multipart or whatever else, but the basis of routing it will.
But you don't need it obviously. Going back to your sample.
Imagine you have a route
post "save_payment_info", to: "payments#save_cc", as: :cc_save
Then a controller:
payments_controller.rb
def save_cc
cc_number_from_form = params[:CardNumber]
end
So you'll be able to access your form fields (as long as they're named correctly) on the params hash inside the controller.
You can do the same with Ajax and return a JSON response, etc.
I need to pass an array in a params, possible? Values can be, for example, ["1","2","3","4","5"] and these are strings but needs to eb converted to integers later.
I use a react_component in between a rails form_for. The html is like this:
<input type="hidden" name="people_id" id="people_id" value={this.state.people} />
The people array looks like this:
How can I pass the array in the value of the hidden field? The server error I got was
Im trying to do something like this in a model:
ids = params[:people_id]
ids.map do |b|
Foo.create!(people_id: b.to_i)
end
If I ids.split(",").map I get symbol to int error.
Edit:
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
Still not sure what the issue is as nothing works. Here is a minimal reproduction of my code:
This answer is my react component and that's how I add to the array. Still in the component, I have the hidden field:
<input type="hidden" name="[people_id][]" id="people_id" value={this.state.people} />
_form.html.erb:
<%= form_for resource, as: resource_name, url: registration_path(resource_name), :html => { :data => {:abide => ''}, :multipart => true } do |f| %>
<!-- react component goes here -->
<%= f.submit "Go", class: "large button" %>
<% end %>
The story is, guest can select few people during registration in one go. Those people will be notified when registration is complete. Think of it as "I am inviting these people to bid on my tender". Those numbers, in the array, are user_ids.
users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
# POST /resource
def create
super do |resource|
ids = params[:people_id].pop # logs now as "people_id"=>["1,2"]
resource.save!(ids.split(",").map |b| Foo.create!(people_id: b.to_i) end)
end
end
end
New error on line resource.save:
no implicit conversion of Symbol into Integer
Edit #2
If I only have, in the create method:
ids.split(",").map do |b|
resource.save!(Foo.create!(people_id: b.to_i))
end
It works! Foo is created two times each with the correct people_id.
Because I am creating more objects: Bar, I do not know how to do that in:
resource.save!(<the loop for Foo> && Bar.create!())
The flow must be:
Device creates the User
Foo is created with the loop
Bar is created
etc
It has to be done that way as an User object is created on the fly.
In Rails you use parameter keys with brackets on the end to pass arrays.
However you should not concatenate the values as a comma seperated list but rather send each value as a seperate param:
GET /foo?people_ids[]=1&people_ids[]=2&people_ids[]=3
That way Rails will unpack the parameters into an array:
Parameters: {"people_ids"=>["1", "2", "3"]}
The same principle applies to POST except that the params are sent as formdata.
If you want a good example of how this works then look at the rails collection_check_boxes helper and the inputs it generates.
<input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" checked="checked" />
<label for="post_author_ids_1">D. Heinemeier Hansson</label>
<input id="post_author_ids_2" name="post[author_ids][]" type="checkbox" value="2" />
<label for="post_author_ids_2">D. Thomas</label>
<input id="post_author_ids_3" name="post[author_ids][]" type="checkbox" value="3" />
<label for="post_author_ids_3">M. Clark</label>
<input name="post[author_ids][]" type="hidden" value="" />
Updated:
If you intend to implement you own array parameters by splitting a string you should not end the input with brackets:
<input type="hidden" name="[people_id][]" value="1,2,3">
{"people_id"=>["1,2,3"]}
Notice how people_id is treated as an array and the input value is the first element.
While you could do params[:people_id].first.split(",") it makes more sense to use the correct key from the get go:
<input type="hidden" name="people_id" value="1,2,3">
Also you don't really want to wrap the "root" key in brackets. Thats used in rails to nest a param key in a hash eg. user[name].
I am quite new to Ruby, but have some experience with programming. I am trying to figure out how to pass a variable collected in a form (SEARCH) using POST, to its controller (API) and then output it into another view (RESULT) that is also in the same controller.
I know the variable makes it to the API controller, because it shows up in the server log. But I can't figure out why it won't pass from there as an instance variable to the Result.html.erb page.
Routes.rb
Remixr::Application.routes.draw do
get "api/search"
post "api/result"
end
search.html.erb
<form action = "result" method="post">
Zip Code: <input type = "text" size = "5" name = "zip_code" />
Search Range: <input type = "text" size = "3" name = "range" />
<input type = "submit" value="Search" />
<input type = "reset" value="Reset Form" />
</form>
result.html.erb
Zipcode = <%= #zip_code %>
Radius = <%= #range %>
api_controller.rb
def search
end
def result
#zip_code = zip_code
#range = range
end
end
I know this some rudimentary stuff here, but I can't find anyone that shows a form used in one view , POST the form contents to its own controller to use another method in that controller and then output variable made in that method to another view under the same controller. I cut out a lot of the other processing that is going on until I am sure that I can pass variables in the fashion I laid out.
In the controller, use:
def result
#zip_code = params[:zip_code]
#range = params[:range]
end
I have a tableless model that I'm trying to generate some form fields for.
The form looks like so:
= form_for :users, url: users_path do |f|
- books.each do |book|
= f.fields_for :books, book do |bf|
= bf.hidden_field :title, value: book.title
= f.submit "Send"
What I'm expecting to be generated for each field is something like this:
<input name="users[books][][title]" type="hidden" value="Some Book Title">
<input name="users[books][][title]" type="hidden" value="Some Book Title">
<input name="users[books][][title]" type="hidden" value="Some Book Title">
However, what I'm actually getting is
<input name="users[books][title]" type="hidden" value="Some Book Title">
<input name="users[books][title]" type="hidden" value="Some Book Title">
<input name="users[books][title]" type="hidden" value="Some Book Title">
Which means when the form is submitted only the last input field is available as the previous two have been overwritten due to them referencing the same thing.
This works ok when the model has an active record backend but not when it's tableless.
Any suggestions?
I think you need to add this to your users model
def books_attributes= attributes
# do something with attributes
# probably:
# self.books = attributes.map{|k,v|Book.new(v)}
end
And also define persisted? method for Book instance. Make it just to return false.
And add f for your fields_for in view:
= f.fields_for :books, book do |bf|
I hope this will work.
Welldan97 brings up a very important point. You need the persisted? method. I was getting an undefined method for the model name earlier. Check my gist out. It works, but not perfect by any means. https://gist.github.com/2638002
Right now this is pretty hard to do with Rails 3.x. That will change with Rails 4 with the advent of ActiveModel::Model which will give all the base methods for your model to be ActionPack compatable.
However until Rails 4 is released a good standard to make your model ActionPack compatible is the ActionModel::Model module itself. It "should" work with the current stable Rails. Check it out
How you choose to implement this is your decision, but I would probably just download the file and throw it in my application's lib directory. That way I could just include it using
class Book
include ActiveModel::Model
end
Easy Rails Form compatibility for custom models.
Try this:
f.fields_for 'books[]', book do |bf|
I am building a dynamic form builder.. And i have a problem which i can't seem to fix.
So i have a db table called "forms"
forms can have "fields"..
The problem is that when a user creates a new 'field' (click add-field) then it should ajax the new field for .. that field.
The problem is that i can't just do something like this:
<%= Form.fields_for Field.new do |field| %>
<%= field.text_field :name%>
<% end %>
Does anybody have an idea? Yes i watch railscasts, yes i googled, yes i found the "complex-forms' repo on github.
But no luck (yet)
If you want an all javascript approach (instead of calling your server to produce the field names) then basically you just need to increment the field names for any new fields.
For example, if you have
class Form < ActiveRecord::Base
has_many :fields
accepts_nested_attributes_for :fields
and the HTML in the form has an input field that has something like
<label for="form_fields_attributes_0_name">
<input id="form_fields_attributes_0_name" name="form[fields_attributes][0][name]" type="text" />
then you need to write some javascript to make it look like
<label for="form_fields_attributes_1_name">
<input id="form_fields_attributes_1_name" name="form[fields_attributes][1][name" type="text" />
You can do something like
$('#form_fields_attributes_1_name').attr('id').split('_');
and
$('#form_fields_attributes_1_name').attr('name').split(/\]\[/);
to get at those numbers.
Here's an example which is refactored here.