TL;DR Is it possible to prefill from one model in the same form builder to another model? Is there a correct way of solving this problem?
I have a form that takes several methods that requires to be passed in: name, email, bio, location, homepage, work.
Email method will need to be retrieved via Devise user model.
In my new.html.erb, it works fine as normal but it returns nil from the email field whenever I do the following:
<%= form_for :profile, url: profiles_path do |f| %>
...
<div><% if current_user.email.present? %><%= f.label :email %><br>
<%= f.email_field current_user.email %><% end %></div>
<% end %>
ProfilesController.rb:
class ProfilesController < ApplicationController
before_action :authenticate_user!, except: [:show]
before_action :find_profile_by_id, only: [:show, :edit, :update]
after_filter :destroy_user!, only: [:destroy]
def index
if #profile.blank?
render :new
else
render :show
end
end
def new
#profile = current_user.profiles.build
#user = current_user.where('email=?')
end
def create
#profile = current_user.profiles.build(profile_params)
if #profile.save
redirect_to #profile
else
render :new
end
end
def show
end
def edit
end
def update
if #profile.update(profile_params)
redirect_to #profile
else
render :edit
end
end
def destroy
#user.destroy
#profile.destroy
redirect_to root_path
end
private
def profile_params
params.require(:profile).permit(:name, :email, :bio, :location, :homepage, :work)
end
def find_profile_by_id
#profile = Profile.find(params[:id])
end
def destroy_user!
#user = User.find(params[:id])
end
end
Is this the correct solution for this?
Your approach seems generally okay but try changing
<%= f.email_field current_user.email %>
To
<%= f.email_field(current_user, current_user.email) %>
Related
I am building a rails app to learn about nested controllers actions. Hence I have Projects to which Tickets are nested underneath. It's basically a rip-off from Rails Action. Now, I am trying to add edit action in Ticket's controller.
Everything works fine in Projects, ie, all the actions.
Everything seems to work fine in Tickets. As stated earlier, it's a rip-off from Rails Action. So trying learn how to put in correct stuff within blank actions, ie, Edit, Show, Update, and Destroy
When I added edit action in Tickets show page, and clicked on it, it showed the page, but the form fields are blank.
The url path is correct: http://127.0.0.1:3000/projects/2/tickets/2/edit so that means the resources are set up correctly.
How do I fix this so it shows the previous content? My vague understanding is that it may have to do with the form?
Current Tickets Controller
class TicketsController < ApplicationController
#which actions are necessary? learn how to not need set_project set_ticket
before_action :set_project
before_action :set_ticket, only: [:show, :edit, :update, :destroy]
def create
#ticket = #project.tickets.build(ticket_params)
if #ticket.save
flash[:notice] = "Ticket has been created."
redirect_to project_path(#project)
else
flash.now[:alert] = "Ticket has not been created."
render "new"
end
end
def new
#ticket = #project.tickets.build
end
def show
end
def edit
#ticket = #project.tickets.find(params[:id])
end
def update
end
def destroy
end
private
def ticket_params
params.require(:ticket).permit(:title, :description)
end
def set_project
#project = Project.find(params[:project_id])
end
def set_ticket
#ticket = #project.tickets.find(params[:id])
end
end
show.html.erb - Ticket
<h1><%= #project.title %></h1>
<h3><%= #ticket.title %></h3>
<%= link_to "All Projects", projects_path %>
<%= link_to "Edit Ticket", edit_project_ticket_path %>
_form.html.erb - Ticket
<%= form_for([#project, #project.tickets.build]) do |f| %>
<p>
<%= f.label :title %><br/>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
EDIT, I've updated the _form.html.erb to the following code beneath, and it seems to work, ie, it shows the contents to modify. Yay. But when I click on Update Ticket button, it doesn't move beyond the page.
<%= form_for [#project,#ticket] do |f| %>
EDIT AGAIN
I updated the ticket's controller actions for Show and Update, and now it seems to work! Including it for feedback in case this was done incorrectly.
class TicketsController < ApplicationController
#which actions are necessary? learn how to not need set_project set_ticket
before_action :set_project
before_action :set_ticket, only: [:show, :edit, :update, :destroy]
def create
#ticket = #project.tickets.build(ticket_params)
if #ticket.save
flash[:notice] = "Ticket has been created."
redirect_to project_path(#project)
else
flash.now[:alert] = "Ticket has not been created."
render "new"
end
end
def new
#ticket = #project.tickets.build
end
def show
#ticket = #project.tickets.find(params[:id])
end
def edit
#ticket = #project.tickets.find(params[:id])
end
def update
if #ticket.update(ticket_params)
flash[:notice] = "Ticket has been updated."
redirect_to [#project, #ticket]
else
flash.now[:alert] = "Ticket has not been updated."
render "edit"
end
end
def destroy
end
private
def ticket_params
params.require(:ticket).permit(:title, :description)
end
def set_project
#project = Project.find(params[:project_id])
end
def set_ticket
#ticket = #project.tickets.find(params[:id])
end
end
I'm currently running into a problem with my form.
First argument in form cannot contain nil or be empty
in my comments/new which is a partial as _new.html.erb. This is the file:
<% form_for #comment do |f| %>
<%= f.label :body %>
<%= f.text_field :body, placeholder: "Write Message here.." %>
<% end %>
What I'm trying to do is render add a comment to an Article#Show page.
My code:
Comments Controller
class CommentsController < ApplicationController
before_action :find_comment, only: [:show, :edit, :update, :destroy]
def index
#comments = Comment.all
end
def new
#comment = Comment.new
end
def create
#comment = current_user.comments.build(comment_params)
if #comment.save
redirect_to :back
else
redirect_to '/'
end
end
def show
end
def edit
end
def update
if #comment.update(comment_params)
redirect_to '/'
else
redirect_to :back
end
end
def destroy
#comment.destroy
redirect_to "/"
end
private
def find_comment
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:body)
end
end
Articles#Show
<%= render '/comments/new' %>
If there is additional code required on my part. Please ask and I'll edit/update the question with additional files.
All help/explanation is appreciated. Thank you in advance.
First question:
Add into Article#Show
def show
#comment = Comment.new
end
I have two classes of users: "users" and "shops". I want the admin to be a "user" and be able to delete shops, and am running in to trouble.
I was able to get the delete button to show up in shops/index.html.erb if the logged in user was an admin (shown below), but when I try to delete a shop object I get the error The action 'destroy' could not be found for ShopsController
shops/index.html.erb
<% provide(:title, 'All shops') %>
<h1>All Shops</h1>
<ul class="center hero-unit col-md-6 col-md-offset-3 shops">
<% #shops.each do |shop| %>
<li>
<div class= "shop-name pull-left">
<%= link_to shop.name, shop %>
<% if current_user.admin? && !current_shop?(shop) %>
| <%= link_to "(Delete Shop)", shop, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</div>
<div class= "shop-address pull-right">
<p><%= shop.address %> <br> <%= shop.city %>, <%= shop.state %> <%= shop.zip %> <br> <%= shop.phone %></p>
</div>
</li>
<% end %>
</ul>
The destroy action is in the shops controller though:
class ShopsController < ApplicationController
before_action :logged_in_shop, only: [:edit, :update]
before_action :logged_in_user, only: :destroy
before_action :correct_shop, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
#shops = Shop.all
end
def show
#shop = Shop.find(params[:id])
end
def new
#shop = Shop.new
end
def create
#shop = Shop.new(shop_params)
if #shop.save
shop_log_in #shop
flash[:success] = "Thank you for signing up, welcome to ensage!"
redirect_to shop_home_path
else
render 'new'
end
end
def edit
#shop = Shop.find(params[:id])
end
def update
#shop = Shop.find(params[:id])
if #shop.update_attributes(shop_params)
flash[:success] = "Profile updated"
redirect_to #shop
else
render 'edit'
end
end
def destroy
Shop.find(params[:id]).destroy
flash[:success] = "Shop deleted"
redirect_to shops_url
end
private
def shop_params
params.require(:shop).permit(:name, :address, :city, :state, :zip, :email, :phone, :password,
:password_confirmation, :picture)
end
def correct_shop
#shop = Shop.find(params[:id])
redirect_to(root_url) unless current_shop?(#shop)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
How can I allow an admin user to delete a shop?
You have set your destroy method as private, so it is not accessible.
before_action :logged_in_shop, only: [:edit, :update, :destroy]
You probably want to remove :destroy from here, or it will expect that you are logged in as shop in order to destroy it. I'm not sure how your access control works but be careful not to make this publicly accessible.
You have put action destroy in private section, this is why it is invisible. Try moving it up over private keyword
First move destroy action out of private, secondly I cannot see admin_shop method anywhere, either remove this line or define admin_shop method
before_action :admin_shop, only: :destroy
To add admin_shop method
def admin_shop
unless current_user.admin?
flash[:error] = "Not authorized"
redirect_to shops_url
end
end
In your destroy action
def destroy
user = User.find(current_user.id)
Shop.find(params[:id]).destroy
sign_in user, bypass: true
flash[:success] = "Shop deleted"
redirect_to shops_url
end
I have this form where a user input a review. A user must be signed with Facebook to save a review.
I use a before_filter to check if the user is signed in or not.
But I get this error: undefined local variable or method signed_in_user'
.
The other thing is, how do I logged the user in with facebook and the save its review? Without losing and making the user input the same review again.
Review form:
<%= form_for [#school, Review.new] do |f| %>
<%= f.text_area :content %>
<% if current_user %>
<%= f.submit 'Save my review', :class => "btn" %>
<% else %>
<%= f.submit 'Save my review and sign me into facebook', :class => "btn" %>
<% end %>
<%end %>
ReviewsController
class ReviewsController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
def create
#school = School.find(params[:school_id])
#review = #school.reviews.new(params[:review])
#review.user_id = current_user.id
if #review.save
redirect_to #review.school, notice: "Review has been created."
else
render :new
end
end
def new
#school = School.find_by_id(params[:school_id])
#review = Review.new
end
end
ReviewsHelper
module ReviewsHelper
def signed_in?
!current_user.nil?
end
def signed_in_user
unless signed_in?
redirect_to "/auth/facebook"
end
end
end
I am using omniauth to authenticate users from facebook.
include your ReviewsHelper in controller:
class ReviewsController < ApplicationController
include ReviewsHelper #or helper :reviews
before_filter :signed_in_user, only: [:create, :destroy]
def create
#school = School.find(params[:school_id])
#review = #school.reviews.new(params[:review])
#review.user_id = current_user.id
if #review.save
redirect_to #review.school, notice: "Review has been created."
else
render :new
end
end
def new
#school = School.find_by_id(params[:school_id])
#review = Review.new
end
end
Your helper is not included in the controller by default.
You can include it as codeit suggested.
Most people put their before filters in ApplicationController as a private method.
EDIT:
To persist the log in, save it to the session data. Look up sessions in the Rails Guides.
I have meet the same problem before. The helper is to help edit the view layer. The before_filter method cannot be written in the helper by default, unless you write 'include BlbalblaHelper' in the controller.
You Can just write the before_filter method in the application_controller.rb as a private method, or in lib/ folder. I think both of them are better approach for DRY.
This is my first ror app.
I have main page: home.html.erb
I have form there.
<%= form_for(#lead ,:html => {:class => 'check_form'}) do |f| %>
<%= f.text_field :phone, placeholder: 'phone' %>
<%= f.submit "Check car status", class: "btn btn-large btn-primary" %>
<% end %>
Backstory: a customer(I call him Lead can input his phone number and check status of his car which is being repaired now.)
Right now this view home.html.erbis served by static_pages_controller
class StaticPagesController < ApplicationController
def home
end
def help
end
def about
end
def contact
end
end
I have also LeadsController
class LeadsController < ApplicationController
#before_action :signed_in_user, only: [:index, :edit, :update]
#before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: [:index, :edit, :update, :destroy]
def index
#leads = Lead.paginate(page: params[:page])
end
def destroy
Lead.find(params[:id]).destroy
flash[:success] = "record deleted."
redirect_to leads_url
end
def show
#lead = Lead.find(params[:id])
end
def new
#lead = Lead.new
end
def create
#lead = Lead.new(lead_params)
if #lead.save
#sign_in #lead
flash[:success] = "Request successfully created!"
redirect_to #lead
else
render 'new'
end
end
def edit
#lead = Lead.find(params[:id])
end
def update
#lead = Lead.find(params[:id])
if #lead.update_attributes(status: params[:status])
flash[:success] = "Information updated"
redirect_to leads_url
else
render 'edit'
end
end
private
def lead_params
params.require(:lead).permit(:name, :email, :phone, :car_type,
:car_year, :car_manufacturer, :car_model, :photo1, :photo2, :coords )
end
# Before filters
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
def correct_user
#lead = Lead.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
What I want to do when user inputs his phone number to find lead in database with the same phone number and show repair status to user.
But it generates an error:
First argument in form cannot contain nil or be empty
So I got that form_for(#lead.. here #lead is empty.
But what should I do to get rid of this error.?
First argument in form cannot contain nil or be empty
As your view(home.html.erb) is served by static_pages#home, you should initialize #lead in the static_pages#home action
def home
#lead = Lead.new
end