I try to create a project page with a form to send invitation to other users. The Owner (who have created the project) can invite other users to participate to the project.
Right now, Here is the code :
views/projects/show.html.erb
<div class="container">
<h3> <%= #project.title %> </h3>
<h6> Créé par <%= link_to #project.owner.username, user_path(#project.owner) %> </h6>
<hr>
<h3> Inviter des utilisateurs au projet </h3>
<!-- form for search users -->
<%= form_tag new_invite_path, method: :post, :class => 'form-inline' do %>
<div class="form-group">
<%= text_field_tag :search, params[:search], size: 30, class: 'form-control' %>
</div>
<%= submit_tag 'Ajouter au projet', class: 'btn btn-success' %>
<% end %>
<!-- end form for search users -->
<!-- display users results -->
<% #users.each do |user| %>
<p> <%= user.username %> | <%= user.email %> </p>
<% end %>
<!-- end display results -->
</div>
controllers/projects_controller.rb
class ProjectsController < ApplicationController
def show
#project = Project.find(params[:id])
#users = User.search(params[:search])
end
def new
#project = Project.new
end
def create
#project = Project.new(project_params)
#project.owner = current_user
#project.members = []
if #project.save
puts #project
redirect_to user_path(current_user)
else
puts 'something went wrong'
puts #project.errors.full_messages
render 'new'
end
end
private
def project_params
params.require(:project).permit(:title, :description, :client, :deadline, :owner, :members)
end
end
On the project page, I have an Ajax form to find all the users, with their username and email.
Now, when I submit this form, I want to create an invitation (a notification, but I haven't begin the notification system). So, I have created this model :
class Invite
include Mongoid::Document
field :email
belongs_to :project
belongs_to :sender_id, :class_name => 'User'
belongs_to :recipient_id, :class_name => 'User'
end
And a controller :
class InvitesController < ApplicationController
def new
#invite = Invite.new(email: params[:search], sender_id: current_user.id)
byebug
#invite.save
end
def create
#invite = Invite.new(params[:search])
if #invite.save
flash[:success] = 'the invitation is send'
redirect_to user_path(current_user)
else
render 'projects/show'
end
end
end
So as you can see, I want to save the invite in my db (MongoDB -> Mongoid), but when I submit the form (on the project/show page), I have this error :
No route matches [POST] "/invites/new"
It's normal, but I want to know :
how to insert data in my database without rendering a view ?
how to have access to user ID with the email adresse ? (which is in the DB)
Thank you !
NB: don't hesitate to ask if you need more code to answer
1) You can insert the data on the database without rendering anything with this line on the controller render :nothing => true, :status => 200
so your create method will be like this
def create
#invite = Invite.new(params[:search])
if #invite.save
flash[:success] = 'the invitation is send'
render :nothing => true, :status => 200
else
render 'projects/show'
end
end
and this is wrong No route matches [POST] "/invites/new" when you try to create something, you will need to go to create, not the new action, just change the url on the form, because you are pointing to the wrong action.
2) If you have an User model and want to load an user by email, you can do something like this
User.find_by_email("the email of the user")
this is your model is User and the column where the email is, is named "email"
Related
I am trying to work in my first implementation using fields_for to manage creating has_many relationship in one form partial. This form partial itself is part of a nested resource
So far, I am able to render, save and edit the form successfully without the fields_for nested form.
When I include the fields_for in the form_for, white-list the params, and build the objects in #new, I get this error in the console as it failed to save and re renders the #new view:
(0.1ms) rollback transaction
What can I do to successfully save the form along with the nested_attributes?
routes.rb
....
resources :projects do
resources :step_ones
resources :step_threes
resources :step_twos
resources :step_fours
resources :step_fives
resources :timelines
end
step_four.rb
class StepFour < ApplicationRecord
belongs_to :project
has_many :ios_devices
accepts_nested_attributes_for :ios_devices
end
ios_device.rb
class IosDevice < ApplicationRecord
belongs_to :step_four
end
_form.html.erb
<div>
<%= form_for([#project, #step_four]) do |f| %>
....
<%= f.fields_for :ios_devices do |d| %>
<div class='form-group'>
<%= d.label :full_name, "Name:"%>
<%= d.text_field :full_name %>
<%= d.label :email, "Email:"%>
<%= d.text_field :email %>
<%= d.label :udid, "UDID:"%>
<%= d.text_field :udid %>
<% end %>
<%= hidden_field_tag :project_id, :value => #project.id %>
<div class='row'>
<span class='col-md-6'><%= button_to "Back", project_path(#project), method: :get, class:'btn btn-primary full-wide-button main-btn' %></span>
<span class='col-md-6'><%= f.submit 'Save Data', class: 'btn btn-primary full-wide-button'%></span>
</div>
<% end %>
</div>
step_fours_controller.rb
class StepFoursController < ApplicationController
def new
#project = Project.find(params[:project_id])
#step_four = StepFour.new
3.times { #step_four.ios_devices.build }
end
def create
#step_four = StepFour.new(step_four_params)
#project = Project.find(params[:project_id])
#step_four.ios_devices.each do |d|
puts d.full_name
puts d.email
puts d.udid
end
#step_four.project_id = params[:project_id]
if #step_four.save
flash[:success] = "Step Five Data Saved"
redirect_to #project
else
flash[:danger] = "Data Not Saved. Please Try Again"
render "new"
end
end
def show
#step_four = StepFour.where(project_id: (params[:project_id])).first
end
def update
#step_four = StepFour.where(project_id: (params[:project_id])).first
#project = Project.find(params[:project_id])
if #step_four.update_attributes(step_four_params)
flash[:success] = "Step Four Data Saved"
redirect_to #project
else
flash[:danger] = "Data Not Saved. Please Try Again"
render 'edit'
end
end
def edit
#step_four = StepFour.where(project_id: (params[:project_id])).first
#project = Project.find(params[:project_id])
end
def step_four_params
params.require(:step_four).permit(:iphone_name, :iphone_nickname, :android_name, ios_devices_attributes: [:id, :full_name, :email, :udid])
end
end
After realizing that the error was upon the save method, I tried to force the issue and raise an exception with a shebang ! . I received a Validation error that lead me to this question:
Error: Validation failed: Images imageable must exist , rails-5.0 , paperclip-5
I needed to add optional: true to the belongs_to: step_four in the ios_device model since, I believe that the object doesn't exist yet.
Now everything is working
I have a nested resource placed in a nested form(for email input), and want to send emails using User Mailer. I am facing problems completing following challenges:
1) Have 10 input field generated by :fields_for on my invitation/new page in order to send up to 10 emails at a time.
2) After submission, cycle through the submitted emails and send an email to each of the submitted entries.
3) After emails have been sent, I have no use for the #invitation in the database and want to destroy it.
So far I have the following code:
The Models
class Scoreboard < ActiveRecord::Base
has_many :invitations
accepts_nested_attributes_for :invitations
end
class Invitation < ActiveRecord::Base
belongs_to :scoreboard
def send_invitation_email
UserMailer.send_invitation(self).deliver_now
end
end
The new.html.erb(invitations)
<%= form_for [#scoreboard, #invitation] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.fields_for :invitations do |invites| %> <!-- this gives me one field. Need 10 fields to accept up to 10 emails -->
<div>
<%= invites.label :recipient_email %>
<%= invites.text_field :recipient_email %>
</div>
<% end %>
<%= f.submit "Send Invitation", class: "btn btn-primary" %>
<% end %>
The Invitations Controller
class InvitationsController < ApplicationController
def new
#scoreboard = Scoreboard.find(params[:scoreboard_id])
#invitation = #scoreboard.invitations.build
end
def create
#scoreboard = Scoreboard.find(params[:scoreboard_id])
#invitation = #scoreboard.invitations.build(invitation_params)
if #invitation.save
#invitation.send_invitation_email
flash[:success] = "Invitation sent successfully"
redirect_to new_scoreboard_invitation_path
else
render 'new'
end
end
private
def invitation_params
params.require(:invitation).permit(:recipient_email)
end
end
When I submit the form, in development log I get the following example code for the invitation:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"gS+olMC89noaYs0klYTg6IFgJ2cj4apML/NZbdbu2gia/KXjbPyyvSKrEUoj3rEAWxDknlgNmpnaefy7I6Hk3Q==", "invitation"=>{"invitations"=>{"recipient_email"=>"this#hotmail.com "}}, "commit"=>"Send Invitation", "scoreboard_id"=>"89"}
Using the logic that it's a possible collection of hashes within a hash, I came up with the following code in the User Mailer file:
user_mailer.rb
def send_invitation(invitation)
#invitation = invitation
#invitation.each do |key, value|
value.each do | x, y|
mail to: y , subject: "You have been invited"
end
end
end
Thanks in Advance!
Optional Bonus Question:
send_invitation.html.erb
<p>Hi View this Thanks </p> <br></br>
<%= # if someone could provide me a code to a link_to for the url for the scoreboard that the invitation is attached to that would be awesome %>
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 have a nested reviews model with a polymorphic association with majors, careers, and schools. I want users to review these majors, schools, and careers on their show page. In addition, I want them to see all the reviews they've made on their profile page.
I can get the reviews to show but I am having trouble with adding, editing, and deleting them because I want them to be able to do these actions when they see their review on the major, school, career, or their profile page.
Here are my routes:
resources :majors, :schools, :careers do
resources :reviews
end
Here are my associations:
Major.rb, School.rb, Career.rb
has_many :reviews, as :reviewable
Review.rb
belongs_to :user
belongs_to :reviewable, polymorphic: true
User.rb
has_many :reviews
Here is my reviews_controller.rb:
before_filter :reviewable
def index
#reviews = #reviewable.reviews
#major = Major.includes(:reviews => :user).find_by_slug(params[:id])
end
def show
#review = #reviewable.reviews.find(params[:id])
end
def new
#review = #reviewable.reviews.build
#review.user = current_user
end
def edit
#review = #reviewable.reviews.find(params[:id])
raise(ActiveRecord::RecordNotFound, "Access Denied") if #review.user != current_user
end
def create
#review = #reviewable.reviews.build(params[:review])
#review.user = current_user
#reviews = #reviewable.reviews
end
def destroy
#review = #reviewable.reviews.find(params[:id])
#review.destroy
raise(ActiveRecord::RecordNotFound, "Access Denied") if #review.user != current_user
end
def reviewable
#reviewable = if params[:major_id]
Major.find_by_slug!(params[:major_id])
elsif params[:school_id]
School.find(params[:school_id])
elsif params[:career_id]
Career.find(params[:career_id])
end
end
In order to create, view, and edit a review for a major, for instance, they will be doing it on the major show page. This is what I have on majors_controller.rb:
def show
#reviews = Review.includes(:user)
#reviews_most_liked = Review.order("created_at DESC").limit(4)
end
I'm trying to make it so they can add and edit from a modal window inside the major, school, and career show page. Here's what I have in the modal window:
<%= simple_form_for([#reviewable, #review]) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :review %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
I figured it out. The problem was with mapping the right instance variables with the correct action and controller. Most of instance variables were placed in my majors_controller.rb, school_controller.rb, and careers_controller.rb show action. This is what part of my majors_controller.rb show action - I was mistakenly placing them in the create action and delete action. But, once I sat and thought about it I realized it's all happening within the show page. Here's what my controller for my models look like:
def show
#reviewable = #major
#reviews = #reviewable.reviews #show reviews
#reviews_most_liked = #reviewable.reviews.order("created_at DESC").limit(2)
#reviews_most_liked_2 = #reviewable.reviews.order("created_at DESC").limit(2).offset(2)
#review = #reviewable.reviews.build(params[:review]) #create a review
#review.user = current_user #connect the created review to the user
end
Then in my majors show.html.erb page I was able to call the show method by calling the person who gave the review:
<%= review.user.profile_name %>
and the review itself:
<%= review.review %>
That displays the review. I then needed to create, edit and delete. In order to create I just had to get the instance variables correct. Once I got them correct in the right controller and under the correct action (majors controller show action) then in the modal window on the majors show page I called the form partial:
<%= render 'reviews/form' %>
which looks like this:
<%= simple_form_for([#reviewable, #review]) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :review, :input_html => { :class => "span4", :rows => 10 },
label: false,
placeholder: 'Help others by sharing what you\'ve learned as a major.' %>
</div>
<div class="modal-footer">
<button class="btn cancel-modal-review" data-dismiss="modal" aria-hidden="true">Cancel</button>
<%= f.submit 'Share My Review', :class => "submit-feedback" %>
</div>
<% end %>
My app has a user model and a post model, where user has_many posts and posts belong_to users. Posts are displayed on a user's profile page. I'd like for any user to be able to post on his own, or any other user's profile page. However, the problem I'm having is that while I know who is posting (current_user), I don't know whose profile current_user is on. I need to know this in order to assign the new post to that user's posts. How do I extract user id information from the profile currently being viewed, so I know where to assign the new post?
My micropost controller looks like:
class MicropostsController < ApplicationController
before_filter :authenticate_user!
def create
#user_of_page = User.find_by_name(params[:id])
#micropost = #user_of_page.microposts.build(params[:micropost])
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to :back
else
redirect_to about_path
end
end
def destroy
end
end
But I'm getting a NoMethodError: undefined method `microposts' for nil:NilClass. I assume this is because I'm making some mistake with the creation of the user_of_page variable, but I don't know what that is!
SOLUTION
Thanks Sam. I took your advice and ended up doing it like this:
I added a column to my Micropost table called belongs_to_id.
I then passed the id of the user whose profile is being shown from the user show view to the micropost controller using a hidden field in the micropost form, like so:
<%= form_for #micropost do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<div class="field">
<%= f.label :content, "Why that mood?" %>
<%= f.text_area :content %>
</div>
<div class="field">
<%= f.hidden_field :author, :value => current_user.name %>
<%= f.hidden_field :belongs_to_id, :value => #user.id %>
<%= f.hidden_field :agree, :value => "0" %>
<%= f.hidden_field :disagree, :value => "0" %>
<%= f.hidden_field :amused, :value => "0" %>
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<% end %>
I then used this id value to search for the user to assign the post to, in the micropost controller, like so:
class MicropostsController < ApplicationController
before_filter :authenticate_user!
def create
#user_of_page = User.find(params[:micropost][:belongs_to_id])
#micropost = #user_of_page.microposts.build(params[:micropost])
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to :back
else
redirect_to about_path
end
end
def destroy
end
end
Magic! Thanks again, you helped me to see it in the right way.
I would do it like this:
class profiles_controller < AC
...
def show
#profile = User.find(params[:id]).profile || current_user.profile
#post = Post.new
end
..
end
/profiles/show.html.erb
...
Name: <%= #profile.full_name %>
...
<%= form_for #post do |f| %>
<%= hidden_field_tag #profile.user %>
...
<% end %>
class microposts_controller < AC
def create
profile_user = User.find(params[:user_id]) # Owner of the profile current_user is on
..
end
end
Not tested. Hope this helps.