I have a RoR application, and the scaffold generation gave me new and edit actions for my model. In the views, there is a _form.html.erb. This form has inputs for two fields that also happen to be attr_accessible but no inputs for fields like created_at, updated_at and id.
I want to generate some custom other forms and views for all my models. I want to know how to programmatically find the fields that should be set manually, and which fields are set by Rails. If I have a model Widget, then Widget.columns gives all the fields.
How does Rails scaffold generation know which fields to put in the form. Also, is there code which determines how "created_at" and "updated_at" are set? Or is this done by the DB?
Update:To clarify, I want to do to things specifically:
I am generating forms for uploading a large number of rows/entities. So I need to know which fields to include in the form. Is it always Widget.accessible_atributes the fields to be set manually?
I need to know which fields to include automatically. If I use the new method of the model, created_at, updated_at, and id are set automatically. I want to load 1000's of rows in the table I will do something like and SQL load file command and I think I need to set created_at and updated_at but not id. How do I know which fields to set. I am looking for some hypothetical method like
>> Widget.auto_columns
# returns {:created_at => '04/12/2013 9:29pm', :updated_at => '04/12/2013'}
Update 2: Trying to see how scaffolding is done I see that in gems/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb, the code uses something like an attributes array that contains only the attributes to show in the form.
<% attributes.each do |attribute| -%>
<div class="field">
<%%= f.label :<%= attribute.name %> %><br />
<%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
</div>
<% end -%>
<div class="actions">
<%%= f.submit %>
</div>
<%% end %>
I think the attributes array is being generated in scaffold_generator.rb with thor's argument method.
How does Rails scaffold generation know which fields to put in the
form.
When generating a scaffold, you generate it like this::
rails generate scaffold TableName attribute:type_of_attribute attribute2:type_of_attribute
And you can concatenate as many attributes as you wish.
Also, is there code which determines how "created_at" and
"updated_at" are set? Or is this done by the DB?
The timestamps (created_at, updated_at) and id are set by Rails automatically.
They will always be added to your database (unless you want to remove the timestamps in the migration files manually, but the id will always stay).
Also you can set some fields in your Models (Tables) that will be automatically generated, but you have to write code for that.
About accessible attributes, although i don't know the use of it:
Photo.accessible_attributes.each { | attribute | puts attribute if attribute.length > 0 }
For some reason it gives me the first value "", so i just escaped it like that.
Also more on attributes and accessibility and counting columns:
Retrieving Rails Model Column Names
How can you discover accessible attribute names from a model instance?
Related
I already generated a scaffold in Rails.
Now, a bit later, I want to add a new field to the scaffold.
How to do that easily?
The idea of scaffolds is to get you up and running quickly, but once you start editing the files you probably don't want to be re-scaffolding things.
That said, adding new fields is usually a 3 step process, add the field to the database, add the field to the form, add the field to the permitted list of fields in the controller. Here's what this looks like:
Add the field to the database
From the terminal, type in rails generate migration AddNAMEToMODELS NAME:TYPE. This will add a field named NAME to the MODELS model and its type with be TYPE. This will create the migration file in db/migrations/TIMESTAMP_AddNAMEToMODEL.rb. A real example of this would be rails generate migration AddBirthdateToUsers birthday:date
Add the field to the form
To be able to edit the new field, you will want to add it the the form, which is located at app/views/MODELS/_form.html.erb. The default format for this new field would be:
<div class="field">
<%= form.label :name %>
<%= form.FIELD_TYPE :name %>
</div>
Add field to permitted list in controller
Strong Parameters is a feature that ensures user cannot submit arbitrary data. It allows you to have a white list of permitted fields. This is usually done in a MODEL_params method in you controller. All you need to do in most cases is add the field to the list:
Before:
def category_params
params.require(:user).permit(:email)
end
After:
def category_params
params.require(: user).permit(:email, :name)
end
I have a Rails model with 2 fields: 'name' and 'bucket'. Name is a string and bucket is a hash of the form: bucket: {red: 1, green: 2, ...}.
I created a rails form to populate these fields but while name works properly, the rest don't even appear as values.
This is the point that it doesn't work, when I am trying to bind a color to a value provided by the user, with default value 0.
<% #board.fetch_all_colors.each do |color| %>
<%= form.label color.to_sym, "#{color}:" %>
<div class="input">
<%= form.text_field :bucket, value: 0.0 %>
</div>
<% end %>
The thing is that when I debug and print params, I only find an empty bucket hash. One problem seems to be that because of the each loop, I only get the last input text.
Edit: I found a workaround that takes me half there. Instead of a text_field, I am using the following:
text_field_tag "bucket[]"
The above uses my input normally and puts it in an array. The problem with that is that since the input is dynamic (and could have labels come and go, I can't guarantee for the position of the array (e.g. that 3rd position is always 'red'). Can I use something like the above but with a hash?
While JSON-like objects are supported by rails DB drivers, the rest of the rails stack doesn't have seamless API's for specifying multi-value column attributes.
You'll need to dynamically build your hash in the controller from custom-defined attributes which don't have a 1:1 mapping to your model.
Alternatively in a more Rails-like fashion, you could use a has_many relation, storing your buckets as a separate model in the database which is joined to your Board model. accepts_nested_attributes_for would help you do this.
I have a Rails project and I use the scaffold to generate my models and CRUD. Now I'm updating some models because I needed more columns or associations.
But I notices that all the columns I've added later than the scaffold are never updated from my form. I added the field manually in the form but nothing is written in the database.
In my case, I have three entities:
Document and People which both belongs to User.
When I generated the scaffold for People, I didn't have the association to User at first, and I added it with the following migration script:
class AddUserRefToPeople < ActiveRecord::Migration
def change
add_reference :people, :user, index: true, foreign_key: true
end
end
And to be able to update through my form, I added the same thing I had in my Document's form which is working very well:
<div class="field form-group">
<%= f.label :user, class: '...' %>
<div class="col-sm-10">
<%= f.select :user_id, options_for_select(User.all.map{|s| [s.firstname, s.id]}), class: '...' %>
</div>
</div>
It seems that the binding between the form and the model doesn't exist for this field (only for People entity because it works for Document).
And I have the same problem on Document on another column. The only pattern I found is the fact that I added those columns after doing the scaffold generation.
Do I miss something ? Do I need to do my update differently ? What is the best practice for adding new columns ?
Let me know if you need more information.
i have a rails form ive made in which the form fields are extracted from the database. i did it like this because for different products, there are different form fields. i could have made one big order form to do it, and if the product field didnt apply to the product it would be left blank, but it seemed like making the fields being called from a database made more sense because there are 30-40 fields per order. anyways the error in which im running into is when im extracting the row field_type, it prints out the literal value instead of putting it in rails. heres what it looks like:
<% #form_field.each do |field| %>
<p>
<%= "f.#{field.field_type}" %> #this prints out f.text_field
</p>
<% end %>
Instead of printing out f.text_field, i would like it to actually make a text field. I tried using raw but no look seeing as thats for html. is there a way to do this in rails?
You'd need to build up the string and send it to f, like f.send(field.field_type) (untested) along with any arguments needed for that particular form field type.
Rails gurus, do you know of a standard solution to this problem I've been struggling with?
In my app, the user can define properties for his objects. So before generating his list of objects (let's say they are books), he can specify which properties he cares about and their potential values, and then for each book he will have to input a legal value for each property. So say I put in for my properties: length (legal values "long", "short") and difficulty ("easy", "hard"). On a different bookshelf, a different list of books could have different properties (cover_color "blue" or "red")
So now I am in my book form. "Add new book on this bookshelf." On the partial, I come up with the list of properties relevant to a new book on this bookshelf (length, and difficulty). Then I look up the legal values for each property. I have a select dropdown in which the user can choose one:
<% for prop in #book.properties %>
<%= prop %> :
<%= f.collection_select :prop_value_select, prop.legal_property_values, :id, :name %>
<%end %>
In my book model, I defined a virtual attribute that will create the "join record" PropertyValue. PropertyValue has legal_property_value_id and book_id.
def prop_value_select=(incoming_id_from_form)
PropertyValue.create!(:legal_property_value_id => incoming_id_from_form, :book=> self)
end
The whole scheme works, except my method is only getting called once, for the first property when the form submits, instead of once for each property.
I am racking my brain... seems very simple, but what's the standard rails way to do something like this?
collect all of the properties into an array and generate the models as a callback?
some magic with a partial for each property?
Thank you!
I think the problem is that you are using a nested model, and all your fields will have the same id's, so rails will only store one nested element.
You should be using fields_for which allows you to handle a nested model.
First you need to specify in your model that it will accept nested attributes. Add the following line
class Book
has_many :properties
accept_nested_attributes_for :properties
end
and in your view you would write something like
<% fields_for :properties do |prop| %>
<%= prop %> :
<%= f.collection_select ...
<% end %>
Hope this helps.