has_one relation controller update rails 3 - ruby-on-rails

I have 2 models. Task and Location
Each task has_one location
task.rb
has_one :location
I am trying to create my controller for the Location model.
This is the new form
<%= form_for(#task.build_Location, :url => task_Location_path(#task)) do |f| %>
Fields
<%= f.submit %>
<% end %>
and the edit form
<%= form_for(#task.Location, :url => task_Location_path(#task)) do |f| %>
Fields
<%= f.submit %>
<% end %>
currently all functions operate properly with the exception of Update.
def create
#location = #task.create_Location(params[:location])
end
def update
#location = #task.locations.find(params[:id])
end
What is the proper way to define this method?

Not exactly sure what you are trying to do but...
you usually want to access #task via it's id; also, if a has_one, it wouldn't be pluralized.
If you were trying to update a task's name to 'something' you could do something like:
def update
#location=Location.find(params[:id])
#location.task.name="something"
#location.save
end

def update
#location = #task.location.update_attributes(params[:location])
end

Related

Rails create additional create action and redirect new to it

Let say I want to create an additional create action. Let's call it create2.
items_controller:
def new
#item = Item.new
and
def create
.....
end
def create2
.....
end
items/form:
<%= simple_form_for (#item) do |f| %>
<%= f.input :name %>
<%= f.submit %>
<%= end %>
routes:
post 'create2', to: 'items#create2', as: :create2
Once I submit form, how can have it to execute create2 instead of create?
for example your model is User with users_controller and you want to create another "new-create"
inside your routes you add some thing like this
resources :users do
collection {
get :new_special_user
post :create_special_user
}
end
inside your users_controller you create 2 methods
def new_special_user
end
def create_special_user
end
inside new_special_user.html.erb, with url that will direct to create_special_user method in user contoller, below is the sample
<%= form_for #user, url: create_special_user_users_path do |f| %>
<% end %>

Rails, populate database with associated models on one form

I have looked at various answers to similar questions and haven't quite cracked it.
A wine model is defined with has_one :register, :dependent => :destroy and rightly or wrongly I have added accepts_nested_attributes_for :register. A register is defined with belongs_to :wine.
The code within wines_controller.rb for create is:
def new
#wine = Wine.new
#register = Register.new
def create
#wine = Wine.new(wine_params)
#register = #wine.registers.build(register_params)
respond_to do |format|
if #wine.save
#success
else
format.json { render json: #wine.errors, status: :unprocessable_entity }
format.json { render json: #register.errors, status: :unprocessable_entity }
end
end
end
My form for creating a new wine has the following code:
<%= simple_form_for #wine do |f| %>
# various working elements
<div class="field">
<% f.fields_for :register do |r| %>
<%= r.label :short_name %>
<%= r.text_field :short_name %>
<%= r.label :barcode %>
<%= r.text_field :barcode %>
<% end %>
</div>
When this form is called up no fields are created from the f.fields_for command but this block is executed because I can add test buttons within it to prove it is accessed.
If I try to create a wine I get the following error message:
undefined method `registers' for #<Wine:0x007f1204375330> Did you mean? register register= register_id
I believe that using .build is there to ensure data integrity: I don't want to create a wine that does not have a corresponding register. I have tried thinking about it nested attributes but that seems to be considered a bad plan by many. This current approach feels correct but I think I am missing some understanding of syntax at the very least.
At a later date it will be necessary to have other models linked to register that will not be associated to wines. I was considering a similar approach but I am happy to be told to rethink!
If I understand you correctly you have 2 issues:
Firstly fields for register aren't being displayed - this is partly because #wine.register is nil.
You should change your new action to:
def new
#wine = Wine.new
#wine.register = Register.new
In addition because you are using simple_form_for you will need to use simple_fields_for instead of fields_for
Your second issue that results in the exception tells you everything... you are trying to access #wine.registers, and not #wine.register
Change in your create method to:
#register = #wine.register.build(register_params)
This will fix that issue ... however ... all you really need to do is build the #wine object from your params - your params should be configured to permit the right nested attributes - if it is set up correctly the register object will also be built when building the #wine object.
Your model is already set to accept_nested_attributes and thus will also validate and save the register object when calling #wine.save - no need to explicitly save the register object.
You should have something like:
def wine_params
params.require(:wine).permit(
:attribute1, :attribute2,
register_attributes: [:id, :short_name, :barcode])
end
Try this
Wine and Register models
class Wine < ApplicationRecord
has_one :register, inverse_of: :wine, :dependent => :destroy
accepts_nested_attributes_for :register
end
class Register < ApplicationRecord
belongs_to :wine, inverse_of: :register
validates_presence_of :wine
end
Wines Controller
class WinesController < ApplicationController
def new
#wine = Wine.new
#wine.build_register
end
def create
#wine = Wine.new(wine_params)
if #wine.save
redirect_to #wine
else
render :new
end
end
private
def wine_params
params.require(:wine).permit(:name, register_attributes: [:simple_name])
end
end
My wine_params are specific for
rails g model wine name:string
rails g model register name:string wine_id:integer
Lastly wine form should look like this
<%= form_for #wine do |f|%>
<p>
<%= f.label :name%>
<%= f.text_field :name%>
</p>
<%= f.fields_for :register do |r|%>
<p>
<%= r.label :simple_name%>
<%= r.text_field :simple_name%>
</p>
<% end %>
<%= f.submit %>
<% end %>
So you can modify wine_params and form partial for your application specifics

Undefined method 'to_key' error using form_for

I am getting the following error when trying to use form_for in my Rails application:
undefined method `to_key' for #<Table::ActiveRecord_Relation:0x8a09ca8>
My config/routes.rb is:
root 'welcome#index'
post 'foo', as: 'foo', to: 'welcome#index'
The controller is:
class WelcomeController < ApplicationController
def index
#tables = Table.all
end
def test
#tables = Table.all
end
end
And the welcome/index.html.erb view is:
<p>
<%= form_for #tables, :url => foo_path do |t| %>
<%= t.text_area :name %>
<% end %>
</p>
I've tried to do the url workaround that had been suggested in the documentation, but I'm still getting the same error.
Does anyone know what I am doing wrong? I would like to understand this bug a bit more so I can better deal with it.
As per your code, index is returning a collection. However your view tries to define a form for it. This is unlikely going to be succeed.
Form is for an object, not for collections.
Perhaps you can do something like
def new
#table = Table.new
end
and in new.html.erb
<%= form_for #table do |f| %>
...
<% end %>
And if you would like to stick with index.html.erb with a form. Then you have to edit your routes for index action and also in controller it should be for creating a new object.
def index
#table = Table.new
end
Hope it helps!
I see your code have 3 not true things
As RESFUL standard then:
index action always go through with get action so in route file you should define again same that:
root "wellcome#index"
get "foo", to: "wellcome#index", as: :foo
form_for usually use with model object but not collect as you use #tables, if model object not save into database form_for using to create 1 object to database, otherwise form_for using update that object
if you want create form at index action you can follow me:
def index
#tables = Table.all
#table = Table.new
end
index.html.erb file
<%= form_for #table do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
you need create tables_controller to process request from form send to server. you run: rails g controller tables
In table_controller.rb you write same as:
def create
#table = Table.new table_params
if #table.save
redirect_to root_path, notice: "success"
else
redirect_to root_path, alert: "fail"
end
end
private
def table_params
params.require(:table).permit :name
end
so that. end. Have nice day!

Best practice in creating belongs_to object

Let's say we have the following situation:
class User < ActiveRecord::Base
has_many :tickets
end
class Ticket < ActiveRecord::Base
belongs_to :user
end
For simplicity let's say Ticket has only some text field description and integer user_id. If we open User's views/users/show.html.erb view and inside User controller we have this code which finds correct user which is selected:
def show
#user = User.find(params[:id])
end`
Now inside that show.html.erb view we also have small code snipped which creates user's ticket. Would this be a good practice in creating it?
views/users/show.html.erb
<%= simple_form_for Ticket.new do |f| %>
<%= f.hidden_field :user_id, :value => #user.id %>
<%= f.text_area :description %>
<%= f.submit "Add" %>
<% end %>
controller/tickets_controller.rb
def create
#ticket = Ticket.new(ticket_params)
#user = User.find(ticket_params[:user_id])
#ticket.save
end
def ticket_params
params.require(:ticket).permit(:user_id, :description)
end
So, when we create a ticket for user, ticket's description and his user_id (hidden field inside view) are passed to tickets_controller.rb where new Ticket is created.
Is this a good practice in creating a new object which belongs to some other object? I am still learning so I would like to make this clear :) Thank you.
You should be able to do something like this in your form:
<%= f.association :user, :as => :hidden, :value => #user.id %>
This will pass user_id through your controller to your model and automatically make an association. You no longer need the #user= line in your controller.
Don't forget that the user could modify the form on their end and send any id they want. :)
See https://github.com/plataformatec/simple_form#associations for more info.
How about getting the user from the controller using current_user so that you protect yourself from anyone that would manipulate the value of the user_id in the form. Also I think this way is much cleaner
views/users/show.html.erb
<%= simple_form_for Ticket.new do |f| %>
<%= f.text_area :description %>
<%= f.submit "Add" %>
<% end %>
controller/tickets_controller.rb
def create
#ticket = Ticket.new(ticket_params)
#ticket.user = current_user
#ticket.save
end
def ticket_params
params.require(:ticket).permit(:user_id, :description)
end

Controller and routes issues in my rails app

I have an app where users can create courses, and each course has_one syllabus. How could I go about configuring my courses and syllabuses (I know it's Syllabi but apparently Rails doesn't) controller, and my routes, so on a course's page there is a link to create or show the course's syllabus, and a link back to the course from the show syllabus page?
In my routes I have:
resources :courses do
resources :syllabuses
member do
put :enroll #this is so users can enroll in the course
end
end
Currently , so the course_id will be saved in the syllabus table in my courses_controller, I have:
def create_syllabus
#course = Course.find(params[:id])
#syllabus = #course.build_syllabus(params[:syllabus])
if #syllabus.save
redirect_to #syllabus, notice: "Successfully created syllabus."
else
render :new
end
end
then in my courses show page I have:
<section>
<% if (current_user.courses.includes(#course) ||
current_user.coursegroups.find_by_course_id_and_role(#course.id, "admin")) %>
<%= render 'create_syllabus' %>
<% end %>
</section>
then in my create_syllabus form (in my courses views folder) I have tried starting it off with:
# I have #course = Course.find(params[:id]) defined in show in the
#courses_controller
<%= form_for #course.create_syllabus do |f| %>
<%= form_for #course.syllabus.create_syllabus do |f| %>
<%= form_for #course.syllabus.create do |f| %>
and I get an undefined method error for each of those.
If you want to create a new syllabus in your show action of a specific course, you can add this to your controllers and views:
courses_controller.rb
#course = Course.find(params[:id])
# Build a new #syllabus object, only if there is none for the current course
unless #course.syllabus
#syllabus = #course.build_syllabus
end
views/courses/show.html.erb
# Show the syllabus name if there is one, or show the form to create a new one
<% if #course.syllabus.name %>
<p>Syllabus: <%= #course.syllabus.name %></p>
<% else %>
<p>Create Syllabus:</p>
<%= form_for([#course, #syllabus]) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<% end %>
syllabuses_controller.rb
def create
#course = Course.find(params[:course_id])
# Build new syllabus object based on form input
#syllabus = #course.build_syllabus(params[:syllabus])
if #syllabus.save
# redirect to /course/:id
redirect_to #course, notice: 'Syllabus was successfully created.' }
end
end
course.rb
class Course < ActiveRecord::Base
attr_accessible :name
has_one :syllabus
end
syllabus.rb
class Syllabus < ActiveRecord::Base
belongs_to :course
attr_accessible :name, :course_id
end
Some things that I left out but you should still include:
validations
rerendering form if something goes wrong
pulling things out into partials
fixing bad code like if #course.syllabus.name
pull out if/else logic into a helper
…

Resources