I work on an application and I have a model with a 'movies' attribute (top 5 movies). When a user tries to edit the top 5 movies I want to display each movie in a different input, but I don't know how to do it (because all 5 movies represent one single attribute)
In my controller
def show
#user = User.find(params[:id])
#user.movies = #user.movies.split(',')
end
In my view
<%= form_for #user do |f| %>
<%= f.label :movies %>
<%= f.text_field :movies[0] %>
.
.
.
<%= f.label :movies %>
<%= f.text_field :movies[4] %>
<% end %>
Of course, this doesn't work!
You can add use a virtual attribute in your User model to handle this, like this:
class User < ActiveRecord::Base
def movies_list
movies.split(',')
end
def movies_list=(list)
self.movies = list.join(',')
end
end
Then in your controller you just do:
def show
#user = User.find(params[:id])
end
And in your view you can handle your form like this:
<%= form_for #user do |f| %>
<%= f.label :movies %>
<%- #user.movies_list.each do |movie| %>
<%= text_field_tag 'user[movies_list][]' %>
<% end %>
<% end %>
That will allow your update action on the users_controller to access the movies array in params[:user][:movies_list], that the model will understand and process.
At last, don't forget to add :movies_list to your permitted params on the controller if you need to.
EDIT: Thanks to #BroiSatse in the comments, as an alternative to the text_field_tag syntax you can use form-builder's f.text_field :movies_list, multiple: true, value: movie
Related
iam new to rails, i have model(welcome) and i want to update the model with single form where the form has duplicate fields .
only second field updates the model ..
Update multiple records in single model with single form_submit
routes
get 'welcome/index'
get 'welcome/new'
post 'welcome/create'
root 'welcome#index'
welcomecontroller
class WelcomeController < ApplicationController
def index
end
def new
#article = Welcome.new
end
def create
#article = Welcome.new(user_params)
if #article.save
redirect_to welcome_new_path
else
render 'new'
end
end
private
def user_params
params.require(:welcome).permit(:name , :descrip )
end
end
welcomeindex view
<%= form_for# article, url: welcome_create_path do |f | %>
<%= f.text_field: name %>
<%= f.text_field: descrip %>
<%= f.text_field: name %>
<%= f.text_field: descrip %>
<%= f.submit "Create" %>
<% end %>
thanks
Only the second set of fields are being updated because you have duplicate names for the fields. Give each field a unique name and it should work.
<%= form_for# article, url: welcome_create_path do |f | %>
<%= f.text_field: name1 %>
<%= f.text_field: descrip1 %>
<%= f.text_field: name2 %>
<%= f.text_field: descrip2 %>
<%= f.submit "Create" %>
<% end %>
You will need to update the controller method user_params accordingly
def user_params
params.require(:welcome).permit(:name1 , :descrip1, :name2 , :descrip2 )
end
I'm having a problem in the model saving with nested attributes.
In the app, there's a Customer, that have 1..n Contacts witch in turn have 1..n Telephones.
I've searched a lot before asking here, and decided to make it save only the Contact first. Well, at first the Customer is stored, but Contact is not. From what I read there's no need to repeat the ... contacts.build from new function in the create, and that the line "#customer = Customer.new(customer_params)" would create and store them both.
Why it's not working? (That's the first question.)
After some modifications and debugging, I found that when I set a second line building Contact (...contacts.build(customer_params[:contacts_attributes])) it's not saved because of an error of 'unknown attribute'. That's because between the hash :contacts_attribute and the content of it, it's added another hash, called ':0' (?). The structure of the hash that comes from the form is this :
":contacts_attribute[:0[:name, :department, :email]]"
I imagine that this hash :0 is for adding more than one Contact instance, that will come in hashes :1, :2 etc.
There's a way to store the Contact instance by getting this :0 hash? (How do I access this hash? Is it "... :contacts_attribute[0]"?)
Below is the relevant code.
Thanks for the attention!
customer.rb
class Customer < ActiveRecord::Base
...
has_many :contacts
accepts_nested_attributes_for :contacts, reject_if: lambda {|attributes| attributes['kind'].blank?}
...
def change_by(user_id)
update_attributes(changed_by: user_id, deleted_at: Time.now, updated_at: Time.now)
end
def delete(user_id)
update_attributes(status: false, changed_by: user_id, deleted_at: Time.now, updated_at: Time.now)
end
private
...
end
customers_controller.rb
class CustomersController < ApplicationController
def new
#customer = Customer.new
#customer.contacts.new
end
def create
user_id = session[:user_id]
#customer = Customer.new(customer_params)
if #customer.save
#customer.change_by(user_id)
flash[:success] = "Cliente cadastrado com sucesso!"
redirect_to customers_url
else
render 'new'
end
end
private
def customer_params
params.require(:customer).permit(:razao_social, :nome, :CPF_CNPJ,
:adress_id, :email_nota, :transporter_id, :observacao,
contacts_attributes: [:nome, :setor, :email])
end
Form
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for #customer do |f| %>
<%= f.label "Dados Básicos" %>
<div class="well">
<%= f.label :razao_social, "Razão Social" %>
<%= f.text_field :razao_social %>
<%= f.label :nome, "Nome" %>
<%= f.text_field :nome %>
<%= f.label :CPF_CNPJ, "CPF/CNPJ" %>
<%= f.text_field :CPF_CNPJ %>
<%= f.label :email_nota, "Email para nota" %>
<%= f.email_field :email_nota %>
<%= f.label :observacao, "Observações" %>
<%= f.text_area :observacao %>
</div>
<%= f.fields_for :contacts do |k| %>
<%= k.label "Contato" %>
<div class="well">
<%= k.label :nome, "Nome" %>
<%= k.text_field :nome %>
<%= k.label :setor, "Setor" %>
<%= k.text_field :setor %>
<%= k.label :email, "Email" %>
<%= k.email_field :email %>
</div>
<% end %>
<%= f.submit "Cadastrar Cliente", class: "btn btn-primary" %>
<% end %>
</div>
reject_if: lambda {|attributes| attributes['kind'].blank?}
No sign of :kind in your form or your customer_params
This might have something to do with it.
Other than that, if you need an add/remove relationship for contacts, check out the cocoon gem. If you only need one, then build that into your fields for:
<%= f.fields_for :contacts, #customer.contacts.first || #customer.contacts.build do |k| %>
The form will then be specific to a single instance of contact.
There's a way to store the Contact instance by getting this :0 hash?
(How do I access this hash? Is it "... :contacts_attribute[0]"?)
You don't need to access it, that's what the accepts_nested_attributes is for. The rest of your code looks ok so sort out the rejection issue at the top and come back if there are still problems, and post the log output - specifically the params hash for the request!
Im writing a game on rails, and am trying to allow a user to create their mine (its a mining game).
I have a table for the users, and a table for mines.
Each user has a ref. ID on their entry, pointing to their mine's ID in the mine table.
I'm getting an error when I try to visit /users/1/mines/new.
undefined method `mines_path'
I can't figure out why.
form in New:
<%= form_for [#mine] do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br>
<p>Depth: <%= #mine.depth %></p>
<%= f.submit "Submit", id: "submit" %>
<% end %>
Controller:
def new
#user = User.find(params[:user_id])
#mine = #user.mines.new
end
def create
#mine = #user.mines.create(mine_params)
if #mine.save
redirect_to users_mines_path
else
render new_mines_path
end
end
routes:
root 'welcome#index'
resources :sessions, only: [:create]
resources :users do
resources :mines
end
resources :tools, only: [:create]
How can I create a new mine THROUGH the user? Am I doing this correctly in my controller?
Thanks!
In your routes you have mines nested inside users so you need to change your form to something like this:
<%= form_for [#user,#mine] do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br>
<p>Depth: <%= #mine.depth %></p>
<%= f.submit "Submit", id: "submit" %>
<% end %>
OR
You can specify url option with your path:
<%= form_for #mine, url: user_mines_path(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br>
<p>Depth: <%= #mine.depth %></p>
<%= f.submit "Submit", id: "submit" %>
<% end %>
For details on forms refer to Form Helpers
Also as #Vimsha pointed out in your controller you need to use .new instead of .create as create will initialize and save your your mine.
def create
#mine = #user.mines.new(mine_params)
if #mine.save
redirect_to user_mines_path
else
render new_user_mine_path
end
end
#user.mines.create will create the mine. So use #user.mines.new
named route for mine index will be user_mines_path
named route for mine show will be user_mine_path(#mine)
named route for new mine will be new_user_mine_path
Contoller:
def create
#mine = #user.mines.new(mine_params)
if #mine.save
redirect_to user_mines_path
else
render new_user_mine_path
end
end
I am trying to reproduce railscast #196 in Rails 4. However, I'm experiencing some problems.
In my example I try to generate a Phonebook - each Person could have multiple PhoneNumbers
These are important parts of my controller:
class PeopleController < ApplicationController
def new
#person = Person.new
3.times{ #person.phones.build }
end
def create
#person = Person.create(person_params)
#person.phones.build(params[:person][:phones])
redirect_to people_path
end
private
def person_params
params.require(:person).permit(:id, :name, phones_attributes: [ :id, :number ])
end
end
and this is my new view
<h1>New Person</h1>
<%= form_for :person, url: people_path do |f| %>
<p>
<%= f.label :name %> </ br>
<%= f.text_field :name %>
</p>
<%= f.fields_for :phones do |f_num| %>
<p>
<%= f_num.label :number %> </ br>
<%= f_num.text_field :number %>
</p>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
needless to say i have has_many :phones and accepts_nested_attributes_for :phones in the my person model and belongs_to :person in the phone model.
I have the following issues:
Instead of 3 phone-number-fields there is just one in the new form
When I submit the form I get an error:
ActiveModel::ForbiddenAttributesError
in the line
#person.phones.build(params[:person][:phones])
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"l229r46mS3PCi2J1VqZ73ocMP+Ogi/yuYGUCMu7gmMw=",
"person"=>{"name"=>"the_name",
"phones"=>{"number"=>"12345"}},
"commit"=>"Save Person"}
In principle I would like to do this whole thing as a form object, but I think if I don't even get it with accepts_nested_attributes, I have no chance to do it as a form object :(
In order to get three phones in the view change form_for :person to form_for #person (you want to use the object you've built here) as follows:
<%= form_for #person, url: people_path do |f| %>
This should fix the ForbiddenAttributes error as well.
And your create action could be:
def create
#person = Person.create(person_params)
redirect_to people_path
end
Update:
<%= form_for :person do |f| %> creates a generic form for the Person model and is not aware of the additional details you apply to a specific object (in this case #person in your new action). You've attached three phones to the #person object, and #person is not the same as :person which is why you didn't see three phone fields in your view. Please reference: http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for for further details.
I wanted to know how to go about have a submit button that will change a boolean attribute, instead of using radio buttons.
As a example if I display a list of 'published' and unpublished' article posts on the Post#index page and I wanted a button called 'Publish' that sets the :is_published field on the Post model to true.
I'm using strong_parameters on Rails 3.2.13
I was thinking in the Post controller I would have
def index
#post = Post.recent
end
def update
#post = Post.find_by_slug(params[:id])
if params[:publish_button]
#post.is_published = true
#post.save
redirect_to root_path
end
end
private
def post_params
params.require(:person).permit(:body, :publish_button)
end
In my Post#index view I have a form_for that has <%= f.submit 'Publish', name: publish_button %>
Here is the view in Post#index
<%= form_for #post do |f| %>
<div class="field">
<%= f.label :body %><br />
<%= f.text_field :body %>
</div>
<div class="actions">
<%= f.submit %>
<%= f.submit_tag 'Publish Post', name: 'publish_post' %>
</div>
<% end %>
The simple model follows
class Post < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
scope :recent, -> { order('updated_at DESC') }
end
But I'm getting an error of Required parameter missing: post
Thanks in advance.
Update
I've added a model and view that corresponds to the question. I hope it helps.
pass in your values as hidden fields, e.g.
= form_for #post do |f|
= f.hidden_field :is_published, value: "1"
= f.submit "Publish"
and if you want it to be inline like a button_to, give it the button_to class:
= form_for current_user.profile, html: { class: 'button_to' } do |f|
...