So currently i have a link_to, where signed in users can click on:
<%= link_to "Enroll", [#task.project, #task] %>
The user has an association with the project, through subscription. To create a new subscription for a user with a project, i wrote some simple form for it.
<%= form_for([#project, #subzz]) do |f| %>
<%= f.hidden_field :project_id, :value => #project.id %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Which works fine and creates the association. However, i want that the user is able to create the subscription whenever he clicks on 'enroll' instead of a second, extra submit button.
Any ideas how to approach this? I thought about using jQuery, but not sure how to inject the ids with it and if its the 'right' way to do it.
Thanks in advance everyone!
EDIT:
When using the method posted as answer, i get:
param is missing or the value is empty: sub
My updatet form:
<%= form_for([#project, #subzz], html: {role: "form", id: "project_form"}) do |f| %>
<%= hidden_field_tag :project_id, :value => #project.id %>
<%= hidden_field_tag :user_id, :value => current_user.id %>
<%= link_to "Enroll", [#task.project, #task], :onclick => "$('#project_form').submit() "%>
<% end %>
subs_controller.rb
class SubsController < ApplicationController
def create
#subz = Sub.create(sub_params)
project = #subz.project
redirect_to root_path
end
private
def sub_params
params.require(:sub).permit(:project_id, :user_id)
end
end
You can be using the existing form and link_to, just edit some like edit the dorm_tag like this
<%= form_for([#project, #subzz], html: {role: "form", id: "project_form"}) do |f| %>
and remove the button into form like this one
<div class="actions">
<%= f.submit %>
</div>
and edit the link_to like this
<%= link_to 'Enroll', "", :onclick => "$('#project_form').submit()" %>
it will work
Update
You can achieve this without a form, comment out this form and edit the link like below
<%= link_to 'Enroll', subs_path(project_id: #project.id, user_id: current_user.id), method: :post %>
and the create method update like below
def create
#subz = Sub.new(sub_params)
if #subz.save
flash[:success] = 'Sub was successfully submited.'
redirect_to root_path
else
flash[:danger] = 'Sub not submited'
redirect_to request.referer
end
end
that is easier
Or if you keep before one with form then the link out from the form and the create method edit like the following
def create
#subz = Sub.new(sub_params)
if #subz.save
flash[:success] = 'Sub was successfully submited.'
redirect_to root_path
else
flash[:danger] = 'Sub not submited'
redirect_to request.referer
end
end
and the form will look like this
<%= form_for([#project, #subzz], html: {role: "form", id: "project_form"}) do |f| %>
<%= hidden_field_tag :project_id, :value => #project.id %>
<%= hidden_field_tag :user_id, :value => current_user.id %>
<% end %>
<%= link_to "Enroll", [#task.project, #task], :onclick => "$('#project_form').submit() "%>
if you confused this [#task.project, #task] on link tag then use direct link
So i came up with the following solution:
I've added the sub handling to the application_controller, so that its availiable for the project_controller. I also added the project, tasks as a reference, so that i am able to redirect to a task via the sub_controller, instead of the project_controller.
application_controller.rb
def create
#subs = Sub.new(sub_params)
project = #subs.project
taskz = project.tasks.first
if #subs.save
redirect_to [taskz.project, taskz]
end
end
private
def sub_params
params.require(:sub).permit(:project_id, :user_id)
end
Inside the show.html.erb from the project_controller, i use the old form:
<%= form_for([#project, #subz] do |f| %>
<%= f.hidden_field :project_id, :value => #project.id %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.submit "Submitted" %>
<% end %>
which works fine. Thanks for any previous help!
Related
I'm trying to use PaperClip inside my application.
I have 3 models: menu, user and pub. I would like the user to be able to add a menu, which is a pdf file, for a pub. So when I upload the pdf file, I would like to have a column in the menu model with the pub id.
menu.rb
has_attached_file :document
validates_attachment :document, :content_type => {:content_type => %w(application/pdf)}
new.html.erb
<div class="page-header"><h1>Upload Menu</h1></div>
<%= form_for ([#pub, #menu]), html: { multipart: true } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="form-group">
<%= f.label :title %>
<%= text_field :title, class: 'form-control' %>
<%= f.label :document %>
<%= f.file_field :document, class: 'form-control' %>
<%= f.submit 'Upload Menu', class: 'btn btn-primary' %>
</div>
<% end %>
routes.rb
resources: pubs do
resources :menus
end
menus_controller.rb
class MenusController < ApplicationController
def index
#menus = Menu.order('created_at')
end
def new
#menu = Menu.new
end
def create
#pub = Pub.find(params[:pub_id])
input = menu_params.merge(pub: #pub)
#menu = current_user.menus.build(input)
if #menu.save
flash[:success] = "Successfully added new menu!"
redirect_to root_path
else
flash[:alert] = "Error adding new menu!"
render :new
end
end
private
def menu_params
params.require(:menu).permit(:title, :document)
end
end
Button for the new page to upload a file
<%= link_to "Upload menu", new_pub_menu_path(#pub), class: 'btn btn-primary' %>
So when I click the button, I get to the new_pub_menu_path(#pub) generated link, but I have an error ..
error
ActionView::Template::Error (undefined method `menus_path' for #<#<Class:0x007f652ce54550>:0x007f652c90c9a8>
Did you mean? user_path):
1:
2: <%= form_for ([#pub, #menu]), html: { multipart: true } do |f| %>
3: <%= render 'shared/error_messages', object: f.object %>
4:
5: <div class="form-group">
What should I do? I tried to use the nested routes so to have in the url the id pub, but when the new.html.file is rendered it gives me that error. I don't know what method menus_path is.
Thanks!
undefined method `menus_path' for
You didn't defined #pub in new method of menus_controller, so #pub is nil in new.html.erb, so is the error. Define it to resolve the issue.
def new
#menu = Menu.new
#pub = Pub.find(params[:pub_id])
end
I have 2 models that are associated with each other via a join table:
class Book < ActiveRecord::Base
has_many :reviews
end
class Reader < ActiveRecord::Base
has_many :reviews
end
class Reviews < ActiveRecord::Base
belongs_to :reader
belongs_to :book
end
Right now, I am able to update a review (which I created manually in the console) on route:
readers/:id/books
The above route was create using rails' member method:
resources :readers
member do
get 'books'
end
end
The update action in reviews controller (reviews#update) is defined like so:
def update
#reader = current_reader
#review = Review.find_by_reader_id(#reader.id)
#book = Book.find(params[:review][:book]
if #reader.books.include?(#book)
#review.update_attributes(review_params)
redirect_to (#reader)
else
flash[:error] = 'You can only edit reviews that belong to you'
end
end
My form_for reviews (reviews#update) looks like this:
Reader Reviews:
<% book.reviews.each do |review| %>
<% if current_reader == (review.reader) %>
<%= review.content %> written by <%= review.reader.name %>
<% if current_reader.reviews.include?(review) %>
<%= form_for ([book, review]) do |f| %>
<div class="field">
<%= f.hidden_field :book, :value => book.id %>
<%= f.text_area :content, placeholder: "compose new review" %>
</div>
<%= f.submit "Update", class: "btn btn-large btn-primary" %>
<% else %>
<%= form_for ([book, review]) do |f| %>
<div class="field">
<%= f.hidden_field :book, :value => book.id %>
<%= f.text_area :content, placeholder: "compose new review" %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
<% end %>
<% end %>
The above works for update. But the 2nd form doesn't.
My intent is to check for a review => if there is one - display a form so that reader can update review; if there isn't one then display a form so that reader can create a review. I have a private method in reviews controller that checks to make sure that a reader has a book before either action is carried out (a before_action method I guess).
The first form works well (the update form) but the second does not - the form is not displayed at all. I have tried various things to get the form to display but no luck. Can you please me determine the best way to resolve this issue?
Thank you very much!
There could be several issues:
elsif
The likely reason your other form won't show will be that your elsif logic won't be correct
I had a look at the .include? Ruby function, and it seems to just be for arrays. Why not try using .exists? instead?
<% elseif !current_reader.reviews.exists?(review) %>
You may have to use review.id or similar to get the correct response. Failing that, why don't you just use <% else %>?
form_for
The second issue may be with your second form_for
<%= form_for [:book, review] do |f| %>
You're currently passing a local variable called book to the form_for builder. Although this is probably correct (I can't find your reference to creating book), I've found it best to put a symbol in the nested form (to show Rails which data it needs to use)
Could you try using else instead of elsif !current_reader.reviews.include?(review)?
Also, it's elsif and not elseif. The problem should not because of this - The page would not have loaded in the first place if this is the case.
UPDATE
I fixed my first error by updating my forms:
Reader Reviews:
<% book.reviews.where(reader_id: current_reader.id).each do |review| %>
<li>
<span><%= review.content %> writen by <%= review.reader.name %> </span
<%= form_for ([book, review]) do |f| %>
<div class="field">
<%= f.hidden_field :book, :value => book.id %>
<%= f.text_area :content, placeholder: "compose new review" %>
</div>
<%= f.submit "Update", class: "btn btn-large btn-primary" %>
<% end %>
</li>
<% if book.reviews.where(reader_id: current_reader.id).size == 0 %>
<%= form_for ([book, book.reviews.build]) do |f| %>
<div class="field">
<%= f.hidden_field :book, :value => book.id %>
<%= f.text_area :content, placeholder: "compose new review" %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
<% end %>
This displays the forms (both post and update). BUT I got this error when I tried to post a new review:
(rdb:35) #review
#<Review id: nil, reader_id: 101, content: "Trial", created_at: nil, updated_at: nil, book_id: nil>
(rdb:35) review_params
Unpermitted parameters: book
{"content"=>"Trial"}
(rdb:35)
So I changed my create action for review to make sure book_id isn't nill:
def create
#reader = current_reader
# #book = Book.find(params[:book_id])
#book = Book.find(params[:review][:book])
if #reader.reviews.where(book_id: #book.id).exists?
flash[:error] = "You already reviewed this book"
else
#review = current_reader.reviews.create(:book_id => params[:book_id.to_i, :content => review_params[:content])
debugger
if #review.save
flash[:success] = "Review created"
redirect_to reader_path(#reader)
else
flash[:error] = "You can only review books that are in your library"
redirect_to reader_path(#reader)
end
end
end
Also changed how I defined review_params:
def review_params
params.require(:review).permit(:content, :book_id)
end
All this changes gave the desired results. My code isn't dry AT ALL but the most important thing to me at this point is getting things to work. Here is to hoping I don't break it again. Thanks for your help #RichPeck
I'm new to rails and trying to make a simple site to start learning. When I submit my form, however, the data isn't saved to the db. I'm really not sure what's wrong, I've been trying to figure it out for a while. If I make a record in the rails console and save it, that one successfully shows up in the db (and on the index page).
calculate.rb:
class Calculate < ActiveRecord::Base
attr_accessible :number, :root
end
calculates_controller.rb:
class CalculatesController < ApplicationController
def index
#calculate = Calculate.all
end
def new
#calculate = Calculate.new
end
def create
#calculate = Calculate.new(params[:calculate])
if #calculate.save
redirect_to '/calculates'
else
render 'new'
flash[:notice] = "Didn't work"
end
end
end
new.html.erb:
<%= form_for(#calculate) do %>
<%= label_tag(:number, "Enter the number") %>
<%= text_field_tag :number %>
<%= label_tag(:root, "root") %>
<%= text_field_tag :root %>
<%= submit_tag("Submit") %>
<% end %>
if you are using form_for, use the form_for syntax
<%= form_for(#calculate) do |form| %>
<%= form.label :number %>
<%= form.text_field :number %>
<%= form.label :root %>
<%= form.text_field :root %>
<%= form.submit "Submit" %>
<% end %>
this will automatically handle the routes if the #calculate is new object it will submit it to create or if it is already saved it will send a put request to edit action
Ah hah! I updated my view to:
<%= form_for #calculate, :url => { :action => "create" } do |f| %>
<%= f.label :number %>
<%= f.text_field :number %>
<%= f.label :root %>
<%= f.text_field :root %>
<%= submit_tag("Submit") %>
<% end %>
And now it works. Awesome.
Right, so http://localhost:3000/reviews/new/5 tells my app to set up a product review for product with ID 5. However, when I submit the form with bogus information I trigger this code in the 'create' action:
#style = Style.find(params[:review][:style_id])
render 'new'
When the page reloads I get the new URL http://localhost:3000/reviews which is fine, but if I submit bogus info AGAIN, then on the next page load #style fails to be assigned.
This is the code in the 'new' action:
#style = Style.find(params[:id])
#review = current_user.reviews.build(style_id: params[:id])
I'm sure this is simple. Breaking for dinner.
I fixed it by adding an if statement to my view... I changed:
<%= f.hidden_field :style_id, :value => params[:id] %>
to:
<% if params[:id] == nil %>
<%= f.hidden_field :style_id, :value => params[:review][:style_id] %>
<% else %>
<%= f.hidden_field :style_id, :value => params[:id] %>
<% end %>
Instead of this:
<% if params[:id] == nil %>
<%= f.hidden_field :style_id, :value => params[:review][:style_id] %>
<% else %>
<%= f.hidden_field :style_id, :value => params[:id] %>
<% end %>
You could simply do this:
<%= f.hidden_field :style_id, :value => #style.id %>
What is the difference between using form_for the following way:
<% form_for #user do |f| %>
<%= f.label :name %>:
<%= f.text_field :name, :size => 40 %>
...
<% end %>
and:
<% form_for :user, :url => {:action => 'create'} do |f| %>
<%= f.label :name %>:
<%= f.text_field :name, :size => 40 %>
...
<% end %>
Does using #user just automatically use CRUD methods for the URL actions?
If you just give a model instance like #user without specifying an action (as in your first example), Rails automatically uses the appropriate CRUD action for your form:
If #user is a new, unsaved User object, the form will point to your create action.
If #user is an existing User loaded from the database, the update action will be used instead.
This has the advantage that you can reuse the same form for both your edit and new views without changing the :url parameter for your forms.
As usual, the API docs provide more information.
If you give form_for a symbol without an instance variable it looks for an instance variable with the same name.
The documentation says:
For example, if #post is an existing
record you want to edit
<% form_for #post do |f| %>
...
<% end %>
is equivalent to something like:
<% form_for :post, #post, :url => post_path(#post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
...
<% end %>