I am building a method in which users can review other users and I am using https://github.com/mackenziechild/movie_review as a base
views/profiles/show
<%= link_to "Write a Review", new_user_review_path(#user) %>
views/review/._form
<%= form_for([#user, #review]) do |f| %>
<div class="field">
<div id="star-rating"></div>
</div>
<div class="field">
<%= f.label :comment %><br>
<%= f.text_area :comment %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
class Review < ApplicationRecord
belongs_to :user
end
class ReviewController < ApplicationController
before_action :authenticate_user!
def new
#review = Review.new
end
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
#review.receiver_id=#user.id
#review.save
end
private
def set_review
#review = Review.find(params[:id])
end
def review_params
How do I solve this?
Routes
user_review_index_path POST /users/:user_id/review(.:format)
review#create
new_user_review_path GET /users/:user_id/review/new(.:format)
review#new
Routes.rb
resources :users do
resources :review, only: [:new, :create]
end
hmm, maybe I have to do a member do?
Edit, I was playing around with it, I think it's because the model being reviewed is not being set properly in the controller
def set_receiver
#review.receiver = User.find(params[:receiver_id])
end
Adding something like this gives me a "no resource found" error
How do I set the receiver of the review since it's another user?
Related
I've got a form with a nested one-to-one attribute which I can't save into the dabase. I've been reading SO threads for four hours to try and solve it:
Contact.rb:
class Contact < ApplicationRecord
has_one :address
accepts_nested_attributes_for :address
end
Address.rb
class Address < ApplicationRecord
belongs_to :contact
end
Routes.rb
Rails.application.routes.draw do
resources :contacts do
resources :addresses
end
root :to => 'contacts#index'
end
The form
<%= form_for #contact do |f| %>
<div class="field">
<%= f.label :firstname %>
<%= f.text_field :firstname %>
</div>
<div class="field">
<%= f.label :lastname %>
<%= f.text_field :lastname %>
</div>
<%= f.fields_for :address do |address_fields| %>
<%= address_fields.label :streetname %>
<%= address_fields.text_field :streetname %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Controller:
class ContactsController < ApplicationController
before_action :find_contact, only: [:show, :edit, :update, :destroy]
def index
#contacts = Contact.all
end
def show
end
def new
#contact = Contact.new
#ontact.build_address
end
def create
#contact = Contact.new(contact_params)
if #contact.save
redirect_to #contact
else
render 'new'
end
end
(...)
private
def find_contact
#contact = Contact.find(params[:id])
end
def contact_params
params.require(:contact).permit(:firstname, :lastname,
address_attributes: [:contact_id, :streetname])
end
end
With the above code, nothing is saved and the transaction is rolled back. Earlier on, only the contact-details were saved whereas the address remained nil and the following line gave an error that "streetname" was unknown:
<p><%= #contact.address.streetname %></p>
Your help is much appreciated!
Thanks #fbelanger for leading me to the solution:
I noticed from the contents of "params" that permitted was set on false. I found via Google that Rails 5 requires the following addition in the address model, to the belongs_to line:
class Address < ApplicationRecord
belongs_to :contact, required: false
end
And now it's saved: hurray!
Following the example guides.rubyonrails.org/getting_started.html I receive an error undefined method `articles' for nil:NilClass in attempt of addition of article on the page.
routes.rb
Rails.application.routes.draw do
root :to => redirect('/pages/1')
resources :articles
resources :pages do
resources :articles
end
views/articles/new.html.erb
<h1>New Article</h1>
<%= form_for([#page, #page.articles.build]) do |f| %>
<p>
<%= f.label :item %><br>
<%= f.text_field :item %>
</p>
<p>
<%= f.label :description %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
articles_controller.rb
class ArticlesController < ApplicationController
def new
#article = Article.new
end
def edit
#article = Article.find(params[:id])
end
def create
#page = Page.find(params[:page_id])
#article = #page.articles.create(article_params)
redirect_to root_path if #article.save
end
private
def article_params
params.require(:article).permit(:item, :description)
end
end
What am I doing wrong?
You aren't defining #page in your new action. You need to add something similar to what you've done in create to the new action (and probably the edit action as well).
before_action :load_page
...
protected
def load_page
#page ||= Page.find(params[:page_id])
end
I have a many_to_many association between Articles and Categories, using has_and_belongs_to_many in a Rails 4 app:
Here are the corresponding migration and classes:
class CategoriesArticles < ActiveRecord::Migration
def change
create_table :articles_categories, id: false do |t|
t.belongs_to :category, index: true
t.belongs_to :article, index: true
end
add_index :articles_categories, [:category_id, :article_id]
end
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :articles
end
class Article < ActiveRecord::Base
has_and_belongs_to_many :categories
end
When a user creates a new article, I simply want to give him or her the option to select categories that he/she wants to associate with the new article. I want the user to be able to select these categories with checkboxes.
Here's the ArticlesController:
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, only: [:new, :create, :edit, :destroy, :update]
before_action :verify_own_article, only: [:destroy]
respond_to :html
...
def new
#categories = Category.all
#article = Article.new
respond_with(#article)
end
def create
# Creates article object with current_user_id, initial_comment, and URL
#article = current_user.articles.build(article_params)
# Uses Pismo (gem) to grab title, content, photo of URL
#article.populate_url_fields
if #article.save
flash[:success] = "Article created!"
# Might need to change the location of this redirect
redirect_to root_url
else
flash[:notice] = "Invalid article."
redirect_to new_article_path
end
end
def update
#article.update(article_params)
flash[:notice] = "Article successfully updated."
respond_with(#article)
end
private
def set_article
#article = Article.find(params[:id])
end
def article_params
params.require(:article).permit(:url, :title, :datetime, :content, :photo, :initial_comment)
end
# Ensure that a signed in user can only delete articles that they have posted
def verify_own_article
#article = current_user.articles.find_by_id(params[:id])
end
end
Here's the article new.html.erb view:
<h1>New article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
... and the form partial:
<%= form_for(#article) do |f| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#article.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% #article.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :url %><br>
<%= f.text_field :url %>
</div>
<div class="field">
<%= f.label :initial_comment %><br>
<%= f.text_field :initial_comment %>
</div>
<% #categories.each do |t| %>
<div class="field">
<%= f.label t.name %>
<%= f.check_box "categories[#{t.id}]" %>
<br />
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
However, this is erroring for me, specifically the lines:
<% #categories.each do |t| %>
<div class="field">
<%= f.label t.name %>
<%= f.check_box "categories[#{t.id}]" %>
<br />
</div>
<% end %>
Specifically, it's telling me:
undefined method 'categories[1]' for #<Article:0x007f401193d520> when I try to render the New Article page. How do I fix this? Thanks.
It is better to use Rails collection_check_boxes helper instead of trying to create those checkboxes by hand. This helper already creates all the parameter / markup stuff you need in order to add or exclude items of a HABTM relation, all under the hood. So you might change you view to include the following:
<%= f.collection_check_boxes :categories_ids, #categories, :id, :name %>
Don't forget to add this in your strong parameters declaration (since you'll have to receive the selected categories ids and bind them to your Article model):
params.require(:article).permit(
:url, :title, :datetime, :content,
:photo, :initial_comment, categories_ids: []
)
For further customizations (html styling or structure for each checkbox), please refer to the complete documentation
I hope it helps :)
I try to make my CRM application works and can't figure out where broken part is.
When trying to create new contact, on link '/companies/1/contacts/new'
got 'NoMethodError in Contacts#new'.
Screenshot is attached, see code below. Please help to find mistake..
route.rb is:
Rails.application.routes.draw do
resources :companies do
resources :contacts do
member do
post :new
end
end
end
root 'companies#index'
end
Contacts Controller:
class ContactsController < ApplicationController
before_action :set_company
def index
#contacts = Contact.where(company_id: params[:company_id])
end
def new; #contact = #company.contacts.new; end
def create
#contact = #company.contacts.create(contact_params)
#contact.save ? redirect_to #company : render :new
end
private
def set_company; #company = Company.find(params[:company_id]); end
def contact_params
params.require(:contact).permit(:name, :position, :phone, :email)
end
end
View:
new.html.erb:
<%= render 'form' %>
<%= link_to 'Back', company_contacts_path %>
Form helper:
<%= form_for(#contact) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You need to specify the company as the first argument to form_for:
form_for(#company, #contact)
Then form_for will be able to infer the correct path.
In my project show view I have a button which goes to create a new question associated to this project I am passing its id.
<%= link_to 'Create question', new_question_path(:project_id => #project.id) %>
in my questions controller I have set_project method which set that project I pass in the link:
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
before_action :set_project, only: [:new, :create, :edit]
before_action :set_categories, only: [:new, :edit]
def new
#question = Question.new
#question.answers.build
#project = Project.find(params[:project_id])
end
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
#question = Question.new(question_params)
#question.project = #project
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:question, :question_type,
projects_attributes: [:id, :name, :category_id])
end
# now we are taking all projects, later we have to take the project correspondent (only one)
def set_project
##project_options = Project.all.map{|p| [p.name, p.id]}
if params[:project_id]
#project = Project.find(params[:project_id])
end
end
def set_categories
#category_options = Category.all.map{|c| [c.name, c.id]}
end
end
My view is a bit tricky because if this question is related to a new project I have to show the project name input and also user should select its category, otherwise it gonna show only the project name.
<%= form_for(#question) do |f| %>
<% if #project %>
<div class="field">
<label>Project Name</label><br>
<%= #project.name %>
</div>
<% else %>
<%= f.fields_for :projects do |project_form| %>
<div class="field">
<%= project_form.label :name, 'Project Name' %><br>
<%= project_form.text_field :name %>
</div>
<div class="field">
<%= project_form.label :category_id %><br>
<%= project_form.select :category_id, #category_options %>
</div>
<% end %>
<% end %>
<div class="field">
<%= f.label :question %><br>
<%= f.text_area :question, rows: 3, cols:40 %>
</div>
<div class="field">
<%= f.label :question_type %><br>
<%= f.select :question_type, Question::QUESTIONS_TYPES, prompt: 'Select a question type' %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Even I can submit the question to the database but the project associated is nil. Any suggestions how to make this working will be really helpful.
Thanks
I think you should read the Nested Resources section of the rails guides:
http://guides.rubyonrails.org/routing.html#nested-resources
Essentially though, you need to add your nested resource to your routes.rb file:
resources :projects do
resources :questions
end
You will then be able to link to the new action of the QuestionsController passing the appropriate project along to the controller:
link_to 'New Question', new_project_question_path(#project)
Then in your controller, you can locate the project and create a new question for it:
def new
#project = Project.find(params[:project_id])
#question = #project.questions.new
end
Have a read of the rails guides - they explain most of this stuff pretty well.