Having problems with putting database to use - ruby-on-rails

So I have this books database and a burrows database. In burrows, there is a field for book_id and also a field for user_id, so that I can see who burrowed which book.
Now, I am trying to create a controller and view for it but it is not going well really. Right now the view is looking like this:
<% provide(:title, "Burrow") %>
<b align="center">Choose the name of the book you want t burrow'</b>
<%= form_for(#book) do |f| %>
<div class="forms">
<%= f.name %>
<%= f.check_box(:book_id) %>
<%= f.submit 'Submit!' %>
</div>
<% end %>
But this puts me to the problem where it creates an error because I want to put all books into #books in burrows controller. But I dont really see any other way? \
The final idea would be so that I have all the books displayed and after them a checkbox, so I can select which books I want to burrow. And after that I also want a dropdown menu where all users are listed, I can choose to burrow the book for another user, but the default value would be the logged in user but theres time till that. Right now I am struggline to understand, why my solution for listing books does not work?
Listing my controller here also:
class BurrowsController < ApplicationController
before_action :signed_in_user, only: [:index,:edit,:update, :destroy]
before_action :admin_user, only: :destroy
def index
#burrows = Burrow.all
end
def show
#burrow = Burrow.find(params[:id])
end
def new
#burrow = Burrow.new
end
def create
#burrow = Burrow.new(burrow_params)
if #burrow.save
flash[:success] = "Burrowing a book was successful!"
redirect_to #burrow
else
render 'new'
end
end
def listing
#book_list = Book.all
end
# Private section, makes the page unable to be seen for non logged in users
private
def burrow_params
params.require(:burrow).permit(:user_id, :book_id)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
# Redirecting not logged in user etc.
def signed_in_user
unless signed_in?
store_location
redirect_to '/sessions/new', notice: "Please sign in!"
end
end
end

Right now I am struggline to understand, why my solution for listing books does not work?
I'm not sure what listing you mean. The view you pasted apparently corresponds to the controller action Burrows#new?
So I'm going to tell you what's wrong with your view:
<%= form_for(#book) do |f| %>
This prints a form for a Book, not a Burrow. You could create a new book with this form, but that's certainly not what you're trying to do here.
You'll want to have all these variables in your controller:
def new
#users = User.all
#books = Book.all
#burrow = Burrow.new
end
so you can use collection_select with #users, have a #burrow object to use with form_for, and do a each loop on #books, for instance, like this:
<%= form_for(#burrow) do |f| %>
<% #books.each do |book| %>
<%= f.check_box :book_ids, multiple: true, book.id, nil %>
<% end %>
<%= f.collection_select :user_id, #users, :id, :name, {}, selected: current_user.id %>
<%= f.submit %>
<% end %>
Click the links for documentation on these commands: collection_select, check_box
This is not ideal code, but it's as close to your example as I can get.
I understand if you don't get this right away. Your code is a bit of a mess right now and there's too much wrong with it to be explained in one post and fixed by just one line. You might want to start over, and make a single controller action work before you try to make everything at once.
Sometimes it's better to sit back and really think about what you're trying to achieve, and first lay out how to achieve it inside your head; and only then start programming!
It seems to me that you're using the RailsTutorial by Michael Hartl, so all I can recommend to you right now is, read what you've read again more thoroughly and try to stick to his examples first until you feel confident, before really starting to make your very own application.

Related

How to implement delete of your post and not other user post in Rails

Lets start off with i am new to programming in rails and trying to learn by building a project. I am creating a project that has following and follower capability similar to twitter... I have implemented the option to delete a post. However, it seems that i can delete other people post as well that i am following etc. How can i implement the delete of my own post and have other user have the ability to edit modify and delete their own post.
post.rb
class Post < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 140 } #
default_scope -> { order(created_at: :desc) } # newest tweets / posts first
end
post controller
def destroy
#status_update = Post.find(params[:id])
if #status_update.present?
#status_update.destroy
end
redirect_to root_url
end
home
<%= link_to('Delete', post_path(#p), :method => :delete,data: { confirm: "Are you sure?" } ) %>
i was also looking at something like this:
def owned_post
unless current_user == #post.user
flash[:alert] = "That post doesn't belong to you!"
redirect_to root_path
end
end
Lets say you have a Post model and views all set up:
In your views/posts/show you can set up something like this:
<% if #post.user.id == current_user.id %>
<%= link_to "Edit", edit_post_path(#post), class:"btn btn-success btn-sm" %>
<% end %>
You will still have a small issue, users can still access the form to edit, so now in your views/posts/edit it renders a form so put a condition on it:
<% if user_signed_in? %>
<% if #post.user.id == current_user.id %>
<%= render 'form', tutorial: #post %>
<% end %>
<% else %>
<h1>stop trying to edit others post</h1>
<% end %>
Good question, though there isn't one single answer I can give you. The question of "authorization" of actions in your app is a big one, and there are gems like Pundit that you could look into for a full-fledged solution.
However, it's always good to start with the basics on your own and build up to a bigger solution. What you have already isn't wrong -- just add before_action :owned_post, only: [:delete] (perhaps rename to ensure_post_owner or such) to your controller to enforce your rule.
Another option is to scope your ActiveRecord queries to the set of objects your current user is allowed to operate on. So instead of #post = Post.find(params[:id]), you could do, #post = current_user.posts.find(params[:id]). If the user tries to modify a post they don't own, they'll get back a 404 as if that post simply doesn't exist. This can be a good strategy to avoid letting attackers enumerate which posts are and aren't in your database.
On view specify something like this:
<% if user_signed_in? && current_user.id == #post.user_id %>
# something like edit. links... delete links..
<% end %>
or you can also use gem like: cancancan

Rails: How to check which form in a view was submitted

There are 2 forms on one page. I want an if else statement in the controller to use different params and variable values depending on which form was submitted. From doing a google search the best I came across was to have a value on the submit button.
<%= f.submit "Save" :value => "x" %>
If this is a plausible way I cant find how to make an if else statement for checking if the submit value is 'x'.
Something like
if submit.value == 'x'
do something
else
do something else
end
Really not sure. If there is another way of having an if else statement in the controller to catch witch form was submitted by using an id or name or whatever I'm happy to hear it.
The value of the submit button can be accessed with the help of params[:commit], so you can use it to check which form is submitted.
if params[:commit] == 'x'
do something
else
do something else
end
#Pavan has the direct answer, however if you're evaluating form submissions by their respective submit values, you've got a major issue with your pattern.
Form
Forms should be a way to pass values to your controller, which will then populate the model. You should not have to determine actions based on those values, unless you have different functionality...
#app/views/posts/index.html.erb
<% #posts.each do |post| %>
<%= form_for post do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
<% end %>
The above will create multiple forms, all submitting to the posts#update method:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def update
#post = Post.find params[:id]
#post.update post_params
end
private
def post_params
params.require(:post).permit(:x, :y, :z)
end
end
The values inside those forms don't matter, nor to which post object they were sent; they will all be evaluated in exactly the same way.
--
Actions
The other way around this is to make separate actions for the different forms:
#config/routes.rb
resources :posts do
patch :update_2, on: :member
end
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def update_2
#post = Post.find params[:id]
#post.param = "value"
#post.update post_params
end
end
#app/views/posts/show.html.erb
<%= form_for #post, url: posts_update_2_path(#post) do |f| %>
<%= f.submit %>
<% end %>
You could use something like
<%=f.submit "Basic update", name: "basic-update" %>
<%=f.submit "Security update", name: "security-update" %>
and then check in your controller:
if params.has_key? "security-update"
#do something
elsif params.has_key? "basic-update"
#do another thing
end

Interpolating data in a rails view

I'm a beginner at rails and thus far interplating data in views has been pretty straight forward. I've been introduced to something slightly new as far as how the controllers are setup and as a result I'm not sure how one would go about getting the data to present in the view.
First controller
class PagesController < ApplicationController
def index
#guestbook_entry = GuestbookEntry.new
render "welcome"
end
end
Second controller
class GuestbookEntriesController < ApplicationController
def create
GuestbookEntry.create(guestbook_entry_params)
redirect_to root_path, notice: "Thank you for your entry."
end
private
def guestbook_entry_params
params.require(:guestbook_entry).permit(:body)
end
end
And here is the welcome.html.erb
<h1>Welcome to My Guestbook</h1>
<br>
<%= image_tag("under_construction.gif") %>
<div id="guestbook-entries">
<p>Guestbook Entries:</p>
<ul>
</ul>
</div>
<%= form_for #guestbook_entry do |f| %>
<%= f.label :body, "Guestbook Entry:" %>
<%= f.text_area :body %>
<%= f.submit "Submit" %>
<% end %>
So it wants me to iterate through all the entries and display them on a welcome page that's located in view/pages/welcome.html.erb.
Up to this point I guess I've only been doing basic simple rails applications where the view corresponded with the controller, and followed the typical CRUD setup, where index would hold the #xxx = Xxxx.all and new/create would handle #xxx = Xxxx.new/create/build. I thought I could simply move the PageController's index action to create/new and do
def index
#guestbook_entry = GuestbookEntry.all
render "welcome"
end
To satisfy the test (it looks for render welcome in the index action)
This seems weird but again I admit, I'm a beginner.
If you want to list all the guest book entries on your root page you would do something like:
class PagesController < ApplicationController
def index
#guestbook_entry = GuestbookEntry.new
#guestbook_entries = GuestbookEntry.limit(10).all
render "welcome"
end
end
And in your view you would list them like:
<% if #guestbook_entries.any? %>
<div id="guestbook-entries">
<p>Guestbook Entries:</p>
<% #guestbook_entries.each do |entry| %>
<ul>
<li class="entry"><%= h(entry.body) %></li>
</ul>
<% end %>
</div>
<% end %>
The rest of you application is correct - you should be creating entries in GuestbookEntriesController#create. In many real life applications then the functionality of the standard new and edit actions can actually be a totally different controller.

rails update and create using form template

I would like to know where i am wrong. So i have an form template to edit and update model(more than one)
<%= form_for :Car,#car,:url=>{:controller=>:cargo} do |form| %>
....
<%= form.submit "Save", :class => "submit" ,:class =>"Button_style"%>
<% end %>
And in controller(cargo) i have some method
def index
#cars=Car.find_all_by_UserId(session[:user_id])
if #cars.nil?
end
end
def create_auto
#car = Car.new(params[:Car])
#car.UserId=session[:user_id];
if #car.save
redirect_to :action=>:index
else
render :action => "new_auto"
end
end
def new_auto
#car = Car.new
#car.CarProperty.build
end
def edit_auto
#car = Car.find(params[:id])
if #car.nil?
flash[:notice] = "Empty request"
end
end
def update_auto
#car = Car.find(params[:id])
if #car.update_attributes(params[:Car])
else
render :action => "edit_auto"
end
end
To add new car i use button
<%= button_to "Add car",{:action=>:new_auto},{:class =>"Button_style",:method => "get"} %>
To edit
<%= button_to 'Change', :controller=>:cargo,:action=>:edit_auto,:id=>car.CarId %>
But when i press Save button nothings happen I mean create_auto and save_auto are not run
Honestly, you need to take a step back and learn some Rails conventions, such as method names for RESTful controllers.
Rails, more than many frameworks, will bite you really hard if you fight its conventions. This is usually a good thing, as it can allow for great productivity by not reinventing the wheel all the time, but you need to learn them.
I recommend these resources (no pun intended!):
ActionController Overview
Rails Routing from the Outside In
You are using non-conventional method names. If you want to do so, you'll have to specify them in the form. Otherwise I'd suggest to rename the methods to match rails conventions.
create, update, …

acts_as_commentable examples?

I have a model that I want to be commentable. I am having difficulty creating a form on my model's 'show' view that will allow comments to be created. I am not finding any good or useful examples. Can anyone point me to or show me an example of how to do this?
Example:
A simple blog application. I have a model called Post. It is commentable. So on the 'show' view I want to show a Post and, at the bottom, have the fields that, when completed and submitted, create a new comment associated with the post and put it in the database.
Sounds straightforward and I have it working so I can display comments that I have seeded. I just can't get a form to work to put new ones in. Any help is appreciated.
Lets assume a Post model. Make sure, you have
class Post < ActiveRecord::Base
acts_as_commentable
end
then in the view of say Post#show
<%= form_tag "/posts/add_new_comment" do %>
<%= hidden_field_tag "id", post.id %>
<%= text_area_tag "comment[comment]" %>
<%= submit_tag "Post Comment" %>
<% end %>
then in the PostController
def add_new_comment
post = Post.find(params[:id])
post.comments << Post.new(params[:comment])
redirect_to :action => :show, :id => post
end
and in routes.rb
match "/posts/add_new_comment" => "posts#add_new_comment", :as => "add_new_comment_to_posts", :via => [:post]
Hope this gets u up and running.
This is very, very basic stuff and you clearly need some better structure and approach to your learning. Buying a book, such as Agile Web Development with Rails, is the only real way to learn, otherwise you'll wander from problem to problem without ever actually learning anything well.
Say you have a post that you want to comment.
#routes.rb
map.resources :posts do |post|
post.resources :comments
end
#post_controller.rb
def show
#post.find params[:id]
#comment = #post.comments.new
end
#posts/show.html.erb
<%- form_for [#post, #comment] do |f|-%>
<%= f.text_area :body -%>
<%= f.submit -%>
<%- end -%>
#comments_controller
def create
#post = #post.find params[:post_id]
#comment = #post.comments.new params[:comment]
if #comment.save
redirect_to #post
This is an old question, but I want to throw in my solution as well as the gem's README is still unhelpful after all these years. It builds upon #Kunday's answer. The following will be a tutorial to use the act_as_commentable gem to...
Allow users to create comments under each post.
Show all comments belonging to a post.
This assumes that you already have a working "blog", whether it be pictures or posts. Install gem, then run rails g comment to get started.
Allow users to create comments under each post.
First, inside the model that you want to use commentable gem, add the following line as suggested in the gem's README.
class Post < ActiveRecord::Base
acts_as_commentable
end
Then create a new comment controller with the create action. Please note that the :authenticate_user! is part of devise which is a gem for creating easy authentication. current_user is also part of devise as a helper. It is needed if you want to display the user's name/email under the comment body.
class CommentsController < ApplicationController
before_action :authenticate_user!
def create
post = Post.find_by(id: params[:id])
comment = post.comments.build(comment_params)
comment.user = current_user
if comment.save
flash[:notice] = "Comment has been created."
redirect_to post
else
flash[:alert] = "Comment has not been created."
end
end
private
def comment_params
params.permit(:comment)
end
end
Next, set up the routes. It's just this. This means that when someone sends a post request to comments, we will run to create action inside the comments controller.
post 'comments' => 'comments#create', as: "create_comment"
The as: "create_comment" gives it an alias, so you can do create_comment_path. Now, on the show view of Post, we'll add the form. The divs will help you add css.
<div class="comment-section">
<%= form_tag create_comment_path, method: "post" do %>
<%= hidden_field_tag "id", #post.id %>
<%= text_area_tag :comment %>
<%= submit_tag "Submit" %>
<% end %>
</div>
Now to show each comment under the Post show view.
The divs will help you add css, comment.user.name will work if your User class has a name column. Else, change it to email or whatever identifier you choose to use.
<div class="comment_list">
<% #comments.each do |comment| %>
<%= comment.comment %> <br>
<%= comment.user.name %> <br>
<br>
<% end %>
</div>
And finally, in order for #comments to exist in the show page, go to your Post controller, and under show, add the following:
def show
#post = Post.find_by(id: params[:id])
#comments = #post.comments.all
end
This should be good for the requirements. Good luck.

Resources