followed a tutorial to help me create instances within a controller. In other words transactions are created on the envelope controller. Like comments on a blog post.
Everything is working perfectly, but I don't know how to edit a transaction now or destroy one. All I need is to find how to edit an existing thing. Let me show you what I have so far:
in views/envelopes/edit (the form code was copied from where you can create new transactions)
<% #envelope.transactions.each do |transaction|%>
<%= form_for [#envelope, #envelope.transactions.build] do |f| %> <!--??? NEED EDIT INSTEAD OF BUILD ???-->
<%= f.text_field :name, "value" => transaction.name %>
<%= f.text_field :cash, "value" => transaction.cash %>
<%= f.submit "Submit" %>
<% end %>
<%= link_to "Remove", root_path %> <!--??? WANT TO REMOVE TRANSACTION ???-->
<% end %>
in routes.rb
resources :envelopes do
resources :transactions
end
in transaction controller
class TransactionsController < ApplicationController
def create
#envelope = Envelope.find(params[:envelope_id])
#transaction = #envelope.transactions.build(transaction_params)#(params[:transaction])
#transaction.save
#envelope.update_attributes :cash => #envelope.cash - #transaction.cash
redirect_to edit_envelope_path(#envelope)
end
def destroy
# ???
end
def update
# ???
end
def transaction_params
params.require(:transaction).permit(:cash, :name, :envelope_id)
end
end
def update
#transaction = #envelope.transactions.find(params[:id])
if #transaction.update(transaction_params)
redirect to #envelope, notice: 'Transaction was successfully updated'
else
redirect_to #envelope, notice: 'Transaction was not updated'
end
end
def destroy
#transaction.destroy
redirect_to #envelope, notice: 'Text here'
end
Related
I have 2 models - project and todo, and the project contain many todos. I'm trying to write a form that would add a todo to a specific project, that's selected in the tray.
Unfortunately I get an error
Couldn't find Project with 'id'=
from todos_controller when i redirect to /todos
#project = Project.find(params[:project_id])
/projects/index.html.erb
<h1> Задачи </h1>
<% #projects.each do |project_name|%>
<h3><%= project_name.title %></h3>
<ul>
<% project_name.todos.each do |project_todo| %>
<li>
<p><%= project_todo.text %></p>
</li>
<% end %>
</ul>
<% end %>
<h1> Новая задача </h1>
<%= form_with scope: :todo, url: todos_path, local: true do |form| %>
<p>
<% form.label :text %><br>
<%= form.text_field :title, placeholder: "Название задачи" %>
</p>
<%= form.select( :project_id, options_from_collection_for_select(Project.all, :id, :title)) %>
<p>
ОТМЕНА
<%= link_to form.submit %>
</p>
<% end %>
projects_controller.rb
class ProjectsController < ApplicationController
def index
#projects = Project.all
respond_to do |format|
format.html
format.json {render json: #projects}
end
end
todos_controller.rb
class TodosController < ApplicationController
def index
#todos = Todo.all
respond_to do |format|
format.html
format.json {render json: #todos}
end
end
def update
end
def create
#project = Project.find(params[:project_id])
#todo = #project.todo.create(todo_params)
redirect_to projects_path
end
end
routes.rb
Rails.application.routes.draw do
resources :projects, :todos
root 'projects#index'
end
I also could not display the submit button as a text link.
modify create action as
def create
#project = Project.find(params[:todo][project_id])
#todo = #project.todo.create(todo_params)
redirect_to projects_path
end
if not works then check params hash from server log and check project_id is present in params or not.
Above will work but I think you do not need to find project if you modify create action as
def create
#todo = Todo.create(todo_params)
redirect_to projects_path
end
also define method as
def todo_params
params.require(:todo).permit(:project_id, :title)
end
Your controller expects a project_id parameter which is probably not passed! Try to add the project id to your params hash when you trigger the todos#create method
params[:project_id] is nil because the form you are submitting for todo, so you need to access project_id as
Project.find(params[:todo][project_id]) in create action.
So replace your create action as follow
def create
#project = Project.find(params[:todo][project_id])
#todo = #project.todo.create(todo_params)
redirect_to projects_path
end
Dont forget to include project_id in todo_params method.
EDIT: I managed to delete! i had to define teh instance variable #movies = Movie.find(params[:id]) to the delete method in the controller.
I still can't update though. I get "param is missing or the value is empty: movie"
I forgot to add my contrller! sorry!
I'm trying to replicate one of my in class exercises into another app, for practice.
The idea is to be able to add new movies into a database, and get the option to update their info, and delete them as well. I can add new content, but I can't update them or delete them.
Appreciate any inputs I can get.
Routes.rb
Rails.application.routes.draw do
root "movies#index"
get "/movies", to: "movies#index"
get "/movies/new", to: "movies#new", as: "new_movie"
get '/movies/:id', to: "movies#movie_page", as: "movie_page"
post "/movies", to: "movies#add"
get "/movies/:id/edit", to: "movies#edit", as: "movie_edit"
put "/movies/:id", to: "movies#update"
patch "/movies/:id", to: "movies#update", as: "update_movie"
delete "/movies/:id", to: "movies#delete", as: "delete_movie"
end
Controller
class MoviesController < ApplicationController
def index
#movies = Movie.all
end
def movie_page
#movies = Movie.find(params[:id])
end
def new
#movies = Movie.new
end
def add
#movies = Movie.create(movie_params)
redirect_to movies_path
end
def edit
#movies = Movie.find(params[:id])
end
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def delete
#movies = Movie.find(params[:id])
#movies.destroy
# flash[:notice] = "Shirt was deleted."
redirect_to root_path, notice: "Shirt was deleted."
end
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
# def set_movie
# #movies = Movie.find(params[:id])
# end
end
Form partial
<%= form_for #movies do |m| %>
<p>
<%= m.label :title %><br>
<%= m.text_field :title %>
</p>
<p>
<%= m.label :description %><br>
<%= m.text_field :description %>
</p>
<p>
<%= m.label :year_released %><br>
<%= m.text_field :year_released %>
</p>
<p>
<%= m.submit %>
</p>
<% end %>
Movie page html (individual movies, labeled by IDs)**I can't update or Delete, no route matches Delete.
When I press Update - I get param is missing or the value is empty: movie
<h1><%= #movies.title %></h1>
<h2>Released on : <%= #movies.year_released %> </h2>
<p> <%= #movies.description %> </p>
<%= link_to "Update", movie_edit_path(#movies) %>
<%= link_to "Delete", movies_path, method: :delete %
Edit page *I cant access this link. the form is the problem
<h1>Edit <%= #movies.title %> Info </h1>
<%= render "form" %>
<%= link_to "Cancel Edit", movie_edit_path(#movies) %>
Many thanks guys
def update
#movie = Move.find(params[:id])
#movie.update(movie_params)
redirect_to movie_path(#movie)
end
on your routes. all you need is resources :movies
you are getting param is empty because you have to pass in the id of the movie to update.
The major issue is that you do not load the variable #movies from the DB before you use it.
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def update
#movies.find(params[:id])
#movie.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
Aside from that you have tons of duplication and quite a few idiosyncrasies.
Rails uses these naming conventions for actions:
index
show (not movie_page)
new
create (not add)
edit
update
destroy (not delete)
You should follow them unless you have a damn good reason not to.
class MoviesController < ApplicationController
# cuts the duplication
before_filter :set_movie, except: [:new, :index]
def index
#movies = Movie.all
end
# GET /movies/:id
def show
end
# GET /movies/new
def new
#movie = Movie.new
end
# POST /movies
def create
#movie = Movie.create(movie_params)
redirect_to movies_path
end
# GET /movies/edit
def edit
end
# PUT|PATCH /movies/:id
def update
#movie.update(movie_params)
redirect_to #movie, notice: "Shirt was updated."
end
# DELETE /movies/:id
def destroy
#movie.destroy
redirect_to action: :index
end
private
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
def set_movie
# Use the singular form when naming a variable with a single record
# failure to do so may result in tarring and feathering
#movie = Movie.find(params[:id])
end
end
So, I'm running into a fairly simple problem, where I cannot enter some simple form values into my SQLite DB (Rails).
Interestingly, the code doesn't fail - I submit the form, and am redirected successfully to the correct URL - and a record IS inserted into the DB, but the columns "name, type and user_id" are not filled with anything. To clarify, the columns are blank, for that new record.
If I comment out the code in the "create" and simply spit out the params (render plain: params[:plan].inspect) I do see all the correct parameters filled out, so I have a feeling there must be something wrong in the line:
#plan = Plan.new(params[:plan])
I'm really stuck here, any guidance would be much appreciated!
The create form
<h1> Create a new plan </h1>
<%= form_for :plan, url: plans_path do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :type %><br>
<%= f.text_field :type %>
</p>
<%= f.hidden_field :user_id, :value => current_user.id %>
<p>
<%= f.submit %>
</p>
<% end %>
plans_controller.rb
class PlansController < ApplicationController
def index
#plans = Plan.all
end
def show
#plan = Plan.find(params[:id])
end
def new
#plan = Plan.new
end
def create
#render plain: params[:plan].inspect
params.permit!
#plan = Plan.new(params[:plan])
if #plan.save
redirect_to #plan
else
redirect_to dashboard_path, :notice => "Plan NOT Created!"
end
end
end
The Model
class Plan < ActiveRecord::Base
end
Edit the plans_controller.rb:-
def create
#render plain: params[:plan].inspect
#plan = Plan.new(plan_params)
if #plan.save
redirect_to #plan
else
redirect_to dashboard_path, :notice => "Plan NOT Created!"
end
end
private
def plan_params
params.require(:plan).permit(:name,:type,:user_id)
end
Change the field name type as :-
rails g migration rename_fields_in_plans
class RenameFieldsInPlans < ActiveRecord::Migration
def change
rename_column :plans, :type, :plan_type
end
end
Then run the command:-
rake db:migrate
I received help Setting up a polymorphic association
I am now having trouble implementing the submit form and create action. A user just needs to follow and unfollow each model.
In my Follow Controller
class FollowsController < ApplicationController
before_filter :find_supports
def create
#relation = find_supports
#follow = #relation.find(params[:follow])
current_user.follows.follow!(#follow)
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
def destroy
#follows = Follow.find(params[:id]).followable
current_user.unfollow!(#follows)
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
private
def find_supports
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
else
nil
end
end
end
end
In my Follow Form, which is rendered at on my polymorphic models
EDIT
<%= form_for #cause.follows.build(params[:follow]) do |f| %>
<div><%= f.hidden_field :followable_id %></div>
<div><%= f.hidden_field :followable_type %></div>
<div><%= f.hidden_field :follower_id %></div>
<div class="create-button"><%= f.submit "Follow" %></div>
<% end %> <!-- I now get the values for followable_id and followable_type, but it
wont get grab the follower_id and I get an error in the create action -->
and in my User Model, I have these 3 methods
def following?(follow)
follows.find_by_followable_id(follow)
end
def follow!(followable)
follows.create![] ##I have tried many different params here
end
def unfollow!(followable)
follows.destroy(params[:followable_id]).destroy
end
I cannot get the follower_id, followable_id and followable_type to save properly. Any suggestions?
Thanks in advance, I have spent many hours with this.
Here is how I solved my issues. The answer is using AJAX and Devise helper method current_user
Form Partial
<%= form_for #relation.supports.build(params[:support]), :remote => true do |f| %>
<div><%= f.hidden_field :supporter_id, :value => current_user.id %></div>
<div><%= f.hidden_field :supportable_id %></div>
<div><%= f.hidden_field :supportable_type %></div>
<%= f.submit "Support", :class => "support-button" %>
<% end %>
My Controller
class SupportsController < ApplicationController
before_filter :find_relation
def create
#relation.supports.create!(params[:support])
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
def destroy
#relation.supports.find(params[:id]).destroy
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
private
def find_supports(instance_params)
class_name = instance_params["supportable_type"].classify.constantize
class_name.find(instance_params["supportable_id"])
end
def find_relation
#relation = find_supports(params[:support])
end
end
Also, add a before_filter in all the controllers that render the form to find the correct object. This will allow you use the same form partial with all your polymorphic classes.
def find_supports
#relation = YourClass.find(params[:id])
end
this is my form code:
<%= simple_form_for setup_video(#video) do |f| %>
<% f.fields_for :comment_titles do |t| %>
<%= t.input :title, :label => "Comment Title:" %>
<%= t.button :submit, :value => 'Add', :id => 'add_comment_title' %>
<div class='hint'>Let your listeners know what comments you want by adding a guiding title for them. Pose a question, ask for feedback, or anything else!</div>
<% end %>
<% end %>
I have has_many :comment_titles and accepts_nested_attributes_for :comment_titles, :comments in my model. when I create a new comment_title in the form, the old one is replaced. I want an additional one to be built. How can I do this?
Here are the video controller actions:
def new
#video = Video.new
respond_to do |format|
format.js do
render_to_facebox(:partial => 'add_video')
end
end
end
def create
#video = current_user.videos.new(params[:video])
respond_to do |format|
if #video.save
format.html { redirect_to(#video) }
else
format.html { render :action => "new" }
end
end
end
I think this is actually what is needed:
def update
#video = current_user.videos.find(params[:id])
respond_to do |format|
if #video.update_attributes(params[:video])
format.html { redirect_to(#video) }
format.js
else
format.html { render :action => "edit" }
end
end
end
The edit action here will provide a form which will allow you to edit the existing record as well as its nested attributes. This is why it's replacing the existing object.
If you only want people to add new comment titles then I would recommend building a new object in your edit action like this:
def edit
video = current_user.videos.find(params[:id])
video.comment_titles.build
end
Then this will be available as an additional row in your fields_for call. To only make this show new objects:
<% f.fields_for :comment_titles do |t| %>
<% if t.object.new_record? %>
# stuff goes here
<% end %>
<% end %>
However this restricts people to being able to only add new items in an edit action, which may seen counter-intuitive to some users.