I searched for the answer, but I couldn't find the same problem.
Basically - I'm building a simple CMS, and I'm building a controller with a view, but it isn't working. I can press the submit button, but the form gives no response, it doesn't even output any errors.
I also noticed it changes the url from /pages/new to /pages, but it stays on the form.
Page Controller:
def index
#pages = Page.sorted
end
def show
#page = Page.find(params[:id])
end
def new
#page = Page.new
end
def create
#page = Page.new(page_params)
if #page.save
flash[:notice] = "Page created succesfully."
redirect_to pages_path
else
render('new')
end
end
def edit
#page = Page.find(params[:id])
end
def update
#page = Page.find(params[:id])
if #page.update_attributes(page_params)
flash[:notice] = "Subject updated succesfully."
redirect_to page_path(#page)
render('edit')
end
end
def delete
#page = Page.find(params[:id])
end
def destroy
#page = Page.find(params[:id])
#page.destroy
flash[:notice] = "Page '#{#page.name}' destoyed succesfully."
redirect_to(pages_path)
end
private
def page_params
params.require(:page).permit(:subject_id, :name, :position, :visible, :permalink)
end
new.html.erb:
<%= link_to("<< Back To List", pages_path, :class => 'back-link') %>
<div class = "pages new">
<h2>Create Page</h2>
<%= form_for(#page, :url => pages_path, :method => 'post') do |f| %>
<table summary = "Page form fields">
<tr>
<th> Name: </th>
<td><%= f.text_field(:name) %></td>
</tr>
<tr>
<th> Subject ID: </th>
<td><%= f.text_field(:subject_id) %></td>
</tr>
<tr>
<th> Permalink: </th>
<td><%= f.text_field(:permalink) %></td>
</tr>
<tr>
<th>Position: </th>
<td><%= f.text_field(:position) %></td>
</tr>
<tr>
<th>Visible: </th>
<td><%= f.text_field(:visible) %></td>
</tr>
</table>
<div class="form-buttons">
<%= f.submit("Create Page") %>
</div>
<% end %>
</div>
EDIT:
tried changing the form code to <%= form_for(#page) do |f| %>, but I still have the same problem
I added the #page.save! part of the code and it gave me a error which showed me errors which are deeper down in my code! At least I fixed this problem. Thank you very much.
It seems that the information from your form is not valid, try using save! instead of save in your create action:
def create
#page = Page.new(page_params)
if #page.save!
flash[:notice] = "Page created succesfully."
redirect_to pages_path
else
render('new')
end
end
That will show the error on your logs.
Related
I have a view with a form and a table that displays some data from the database. Whenever I try to access the object from my controller in my view I get undefined method domain for "https://www.lookagain.co.uk/":String. But if do <%#savedHTML = ScrapedPage.all%> everything works fine. I know the I should not do that in the view as it defeats to purpose of MVC but I don't seem to fin a fix.
View:
<%= stylesheet_link_tag "masterstyles.css" %>
<% #url = 'default' %>
<%= form_for #url, :url => {:controller => "page_scraper", :action => "scrape"} do |f| %>
<%= f.text_field (:url) %>
<%= f.submit "Scrape" %>
<% end %>
<%#domain ='default'%>
<%#date ='default'%>
<%= form_for #domain, :url => {:controller => "page_scraper", :action => "compare"} do |f| %>
<%=select_tag 'domain', options_for_select(#savedHTML.collect{ |u| [u.domain, u.domain] })%>
<%=select_tag 'date', options_for_select(#savedHTML.collect{ |u| [u.created_at, u.created_at] })%>
<%= f.submit "compare" %>
<% end %>
<div class="subjects index">
<h2>FGH Page Scraper</h2>
<table class="listing" summary="Links list">
<tr class="header">
<th>ID</th>
<th>link</th>
<th>Created at</th>
<th>Updated at</th>
</tr>
<% #savedHTML.each do |page| %>
<tr>
<td><%= page.id %></td>
<td><%= page.domain %></td>
<td class="center"><%= page.created_at %></td>
<td class="center"><%= page.updated_at %></td>
<td class="actions">
<%= link_to("Delete", {:controller => 'page_scraper', :action => 'delete', :id => page.id}, :class => 'action delete') %>
</td>
</tr>
<% end %>
</table>
</div>
Controller:
class PageScraperController < ApplicationController
require 'nokogiri'
require 'open-uri'
require 'diffy'
require 'htmlentities'
def scrape
#url = watched_link_params[:url].to_s
puts "LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOG#{#url}"
#page = Nokogiri::HTML(open(#url))
coder = HTMLEntities.new
#encodedHTML = coder.encode(#page)
create
end
def index
#savedHTML = ScrapedPage.distinct.pluck(:domain)
end
def show
#savedHTML = ScrapedPage.distinct.pluck(:domain)
end
def new
#savedHTML = ScrapedPage.new
end
def create
#savedHTML = ScrapedPage.create(domain: #url, html: #encodedHTML, css: '', javascript: '')
if #savedHTML.save
puts "ADDED TO THE DATABASE"
redirect_to(root_path)
else
puts "FAILED TO ADD TO THE DATABASE"
end
end
def edit
end
def upadate
end
def delete
#savedHTML = ScrapedPage.find(params[:id])
end
def destroy
#savedHTML = ScrapedPage.find(params[:id])
#savedHTML.destroy
redirect_to(root_path)
end
def compare
#domain = params[:domain].to_s
puts #domain
redirect_to(root_path)
#timestamp
end
def watched_link_params
params.require(:default).permit(:url)
end
def compare_params
params.require(:domain).permit(:domain)
end
end
The problem is that in your controller you are saving only string-values to #savedHTML variable (pluck will give you only an array of attributes from given objects). Therefore you cant ask "some_string".domain because String class doesn't have a domain method.
If you have a domain method on ScrapedPage object then in your controller action (index or show - whatever you are dealing with) you should replace
#savedHTML = ScrapedPage.distinct.pluck(:domain)
with
#savedHTML = ScrapedPage.select(:domain).distinct
The latter will give you unique ScrapedPage objects based on domain value. Look here for further info and examples.
NB! also a tip for refactoring:
Use strong parameters under private section. Also, if you have the same query in your controller twice in different actions then it is better to make it in before_action like this:
class PageScraperController < ApplicationController
before_action :set_saved_html, only: %i[index show]
def index
end
def show
end
private
def watched_link_params
params.require(:default).permit(:url)
end
def compare_params
params.require(:domain).permit(:domain)
end
def set_saved_html
#savedHTML = ScrapedPage.select(:domain).distinct
end
end
This is the error I'm getting:
No route matches [POST] "/specials/1"
I understand that it's not able to produce the post route, or it isn't available.
Here's my view/form code:
<%= form_for(:special, :url => {:action => 'update', :id => #special.id}) do |f| %>
<table class="table table-responsive table-striped table-condensed table-hover" summary="Special form fields">
<tr>
<th>Order</th>
<td><%= f.text_field :order, class: "form-control" %></td>
</tr>
<tr>
<th>Name</th>
<td><%= f.text_field :name, class: "form-control" %></td>
</tr>
<tr>
<th>Description</th>
<td><%= f.text_field :description, class: "form-control" %></td>
</tr>
<tr>
<th>Fine Print</th>
<td><%= f.text_field :fine_print, class: "form-control" %></td>
</tr>
<tr>
<th>Active</th>
<td><%= f.text_field :active, class: "form-control" %></td>
</tr>
</table>
<div class="form-buttons">
<%= submit_tag("Update Special") %>
</div>
<% end %>
Heres's my controller code:
class SpecialsController < ApplicationController
def index
#specials = Special.sorted
end
def show
#special = Special.find(params[:id])
end
def new
#special = Special.new
end
def create
#Instantiation of object using form parameters
#special = Special.new(special_params)
#Save the object
if #special.save
#If success, redirect to index action
redirect_to(:action => 'index')
else
# Redisplay the form so user can fix problems
render('new')
end
end
def edit
#special = Special.find(params[:id])
end
def update
#Find an existing object using form parameters
#special = Special.find(params[:id])
#Update the object
if #special.update_attributes(special_params)
#If succeeds, redirect to index action
redirect_to(:action => 'show', :id => #special.id)
else
# If update fails, redisplay the form so user can fix problems
render('edit')
end
end
def delete
end
private
def special_params
params.require(:special).permit(:name, :description, :fine_print, :active, :order)
end
end
I noticed that there is an update path:
PATCH /specials/:id(.:format) specials#update
I can't figure out why the post route isn't being applied. It's looking for the right #special instance, but it doesn't seem to have the route available. Any advice?
Usually when updating a record, we do a patch request to the route. Your form should look like this:
<%= form_for(#special) do |f| %>
Rails will determine the correct route is PATCH /specials/:id based on the fact that #special has been persisted to the database.
If you decide to use this same form as a partial in your new view, just make sure to add this to your controller:
def new
#special = Special.new
end
That way whether you are on the new route or the edit route, there will always be a #special object for form_for to infer whether to POST to /specials or PATCH /specials/:id
I've been trying to add uploads to my rails project following this article: How To: Secure Upload. Everything seems to work fine, but I am getting a no method error on the index view:
ActionView::Template::Error (undefined local variable or method `f' for #<#<Class:0x007f690e634600>:0x007f690e620718>):
24:
25: <tr>
26: <td><%= resume.name %></td>
27: <td><%= link_to File.basename(f.resume.url), "/uploads/#{f.id}/#{File.basename(f.resume.url)}" %></td>
28: <td><%= button_to "Delete", resume, method: :delete, class: "btn btn-danger", confirm: "Are you sure that you wish to delete #{resume.name}?" %></td>
29: </tr>
30:
app/views/resumes/index.html.erb:27:in block in _app_views_resumes_index_html_erb___1440061793164452865_70044592937660'
app/views/resumes/index.html.erb:23:in_app_views_resumes_index_html_erb___1440061793164452865_70044592937660'
My model:
class Resume < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader # Tells rails to use this uploader for this model.
validates :name, presence: true # Make sure the owner's name is present.
end
My Controller:
class ResumesController < ApplicationController
def index
#resumes = Resume.all
end
def new
#resume = Resume.new
end
def create
#resume = Resume.new(resume_params)
if #resume.save
redirect_to resumes_path, notice: "The resume #{#resume.name} has been uploaded."
else
render "new"
end
end
def download
path = "/#{resume.resume}"
send_file path, :x_sendfile=>true
end
def destroy
#resume = Resume.find(params[:id])
#resume.destroy
redirect_to resumes_path, notice: "The resume #{#resume.name} has been deleted."
end
private
def resume_params
params.require(:resume).permit(:name, :attachment)
end
end
My Index View:
<% if !flash[:notice].blank? %>
<div class = "alert alert-info">
<%= flash[:notice] %>
</div>
<% end %>
<br />
<%= link_to "New Resume", new_resume_path, class: "btn btn-primary" %>
<br />
<br />
<table class = "table table-bordered table-striped">
<thead>.
<tr>
<th>Name</th>
<th>Download Link</th>
<th> </th>
</tr>
</thead>
<tbody>
<% #resumes.each do |resume| %>
<tr>
<td><%= resume.name %></td>
<td><%= link_to File.basename(f.resume.url), "/uploads/#{f.id}/#{File.basename(f.resume.url)}" %></td>
<td><%= button_to "Delete", resume, method: :delete, class: "btn btn-danger", confirm: "Are you sure that you wish to delete #{resume.name}?" %></td>
</tr>
<% end %>
</tbody>
</table>
I've been googling answers for hours and can't seem to track down a solution based on previous answers. Apologies if one was overlooked.
there is a typo in the how-to (and this how-to aslo http://www.tutorialspoint.com/ruby-on-rails/rails-file-uploading.htm) . just rename #resumes -> #resume in the view and the controller.
so i have installed best in place gem in a rails 4 environment and initialised it correctly. (i can click on the name field and the box becomes editable).
I've this code in my admin_namespaced user controller
class Admin::UsersController < Admin::BaseController
def index
#users = User.all
# #columns = User.column_names
end
def show
#user = User.find(params[:id])
end
def update
#user = User.find params[:id]
respond_to do |format|
if #user.update_attributes(user_params)
format.html { redirect_to(user, :notice => 'User was successfully updated.') }
format.json { respond_with_bip(#user) }
else
format.html { render :action => "index" }
format.json { respond_with_bip(#user) }
end
end
end
private
def user_params
params.require(:user).permit(:name,:email,:password,:password_confirmation)
end
end
and basically i want to use it in conjuction with rails datatables gem that i successfully setup, to inline-edit corresponding fields.
this is the html.erb code in my user index view
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= link_to "Back", admin_path %>
<table class="display responsive no-wrap text-center" id="usertableadmin">
<thead>
<tr>
<th>id</th>
<th>Username</th>
<th>Email</th>
<th>Activated?</th>
<th>Admin?</th>
</tr>
</thead>
<tbody>
<% #users.each do |user| %>
<tr>
<td><%= user.id %></td>
<td><%= best_in_place user, :name%></td>
<td><%= user.email %></td>
<td><%= user.activated %></td>
<td><%= user.admin %></td>
</tr>
<% end %>
</tbody>
</table>
here is what the html code looks like on the tag that has the best_in_place initialization.
<span data-bip-type="input" data-bip-attribute="name" data-bip-object="user" data-bip-original-content="Example User" data-bip-url="/users/1" data-bip-value="Example User" class="best_in_place" id="best_in_place_user_1_name">Example User</span>
I dont know for sure but for some reason the fields do not get updated. When i click to change the name it gets reverted to the previous one.
I dont know if its because i have a namespace, admin/users or its because its the index action and not the show action.
any insight is welcome.
I've found the solution,
it seems the error was the update url it was wrong because of the namespace.
What i had to do, was to include url parameter like below
<td><%= best_in_place user, :name, url: "users/#{user.id}" %></td>
I'm trying to show the avatar of each user who has commented in a topic. I pretty much have a Topic Model and a Comment Model. In my index page i have a list of all the topics created and a list of avatar of the user who commented but it only gets the list of the first topic and the images get repeated.
This is what i have in my index but I end up getting the avatar of each comment with repeated images.
<tbody>
<% #topics.each do |topic| %>
<th class="topic"> <%= link_to topic.title, topic %> </th>
<th class="category"><%= topic.category.title %></th>
<th class="users"><%= image_tag topic.user.avatar.url(:thumb)%></th>
<th class="replies"><%= topic.comments.count %> </th>
<th class="replies"></th>
<th class="activities"></th>
<% #comment.each do |comment| %>
<%= image_tag comment.user.avatar.url(:thumb) %>
<% end %>
<% end %>
</tbody>
My comments controller
class CommentsController < ApplicationController
def index
#topics = Topic.all
#comments = Comment.includes(:user)
end
def create
#comment = #commentable.comments.new(comment_params)
#comment.user_id = current_user.id
#comment.save
redirect_to #commentable
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
You are displaying the user of only one comment.
<% #comment.each do |comment| %>
You probably need to get all comments of the topic instead. See below.
<% topic.comments.each do |comment| %>
To avoid N+1 issue, you can eager load the comments too
def index
#topics = Topic.includes(:comments => :user)
end
To display unique users, you can use Array#uniq with a block.
Assuming comments table has user_id, as foreign key,
<% topic.comments.uniq(&:user_id).each do |comment| %>