Ancestry string not being deifined - ruby-on-rails

essentially I have a category that you can add comments to, this category shows a lists of tasks. When You add comments you have the ability to reply to said comment, when you do so and hover the reply link you’ll see something much like:
http://localhost:3000/categories/2/category_comments/new?parent=6
We then take that id, pass it to the reply forum and then assign it to the ancestry string in the database to "nest" the reply. The problem is, the parent id is not being passed to the form. The form's hidden field is blank. Why? We can walk the path this id should take in the following code.
categories_controller
def show
#category = Category.find(params[:id])
#category_comment = #category.category_comments.build
end
This shows the comment on the category page, and passes the parent_id of the comment your replying to, to the form.
When we click reply, we trigger the category_comments#new and #create methods shown below.
category_comments_controller
def new
#category = Category.find(params[:category_id])
#category_comment = #category.category_comments.build(:parent_id => params[:parent_id])
end
def create
#category = Category.find(params[:category_id])
#category_comment = #category.category_comments.create(params[:category_comment].merge(:user_id => current_user.id))
if #category_comment.save
redirect_to project_category_path(#category.project, #category), :flash => {:success => 'Created comment'}
else
redirect_to :back, :flash => {:error => 'Could not create comment'}
end
end
update:
this is no longer a form issue it is a controller issue, dealing with passing the parent_id to the form.

Try this:
<%= link_to 'Reply', new_category_category_comment_path(#category.id, :parent_id => category_comment.id)%>

Do you have has_ancestry defined in your model? I think not having it there would be a valid explanation for this not working.

Some how this magically fixed its self. I am not sure how or what happened, but it magically works now >.>

Related

How to fit a form into a rails show after another form? Multiple same forms

I am making this form for a reply function in a blog-like app with the same recipe as the comment in which it should nest. (Comment recipe)
I get the following error when I try to view my app in the browser:
No route matches {:action=>"index", :post_id=>"10", :controller=>"replies", :comment_id=>nil} missing required keys: [:comment_id]
This is my reply view file for my replies/_form.html.haml
%h5 Reply
= form_for [ #post, #comment, #reply ] do |f|
%p
= f.label :name
%br
= f.text_field :name
%p
= f.label :talk
%br
= f.text_area :talk
%p
= f.submit 'Submit'
This is my replies controller getting a hold on the comments_id much like the recipe said I should do between the comments and the post_id:
class RepliesController < ApplicationController
def create
#reply = Reply.new(reply_params)
#reply.comment_id = params[:comment_id]
#reply.save
redirect_to post_path(#reply.comment.post)
end
end
And this is my id passing in the comments show controller as it is similar in the post show controller. Or should I add something more to the post show controller now?
def show
#reply = Reply.new
#reply.comment_id = #comment.id
end
I tried adding replies though the rails console. They show up neatly, so I think my routes file works. Something with the id's and the handling of the collections isn't going great though. The form part is not working.
I don't like adding gems if I don't have to, I want to understand my app.
EDIT: I should probably add that my app has a view that looks like a indexing-form system in a indexing-form system.
Below the post there are comments - with a form, and below these there are replies - with a form.
EDIT 2: First argument in form cannot contain nil or be empty is what I get now al the time.
EDIT 3: I still can't make my forms under the comments. This is my routes file, maybe it clarifies.
resources :posts do
resources :comments do
resources :replies do
end
end
end
I am debugging now by making print outs and found out that in my _form haml file for a reply rails can find the #post, but not the comment nor replies (but they have to be created of course with the form), while I can get almost exactly the same structure to work in my _form for a comment.
Is it even possible in Rails to have multiple forms printed out on the same page?
Still all help is appreciated!
EDIT 4: I have gotten a little further. Now Rails says:
No route matches {:action=>"index", :post_id=>"2", :controller=>"replies", :comment_id=>nil} missing required keys: [:comment_id]
As a direct effect of changing my show action in the post controller:
def show
#post = Post.find(params[:id])
## create a blank comment
#comment = Phase.new
#comment.post_id = #post.id
##
## The same for a blank reply
#reply = Reply.new
#reply.comment_id = #comment.id
##
end
The last line of this action seems to not make any difference. Now I just need to be able to grab this comment_id in the reply form and then I am done. Nearly a week of struggle.
I believe you may not be getting a #comment.id because you are doing Comment.new(reply_params) and objects only get id fields whens you use .create OR .save after instantiating with new. Let me know if this helps!
Because of this you are getting the nil error for #comment in the form.
EDIT
It seems like you are looking to get the comment_id from the form, another solution would be to get it from the URL by having this happen under comments path. You'd have to nest your resources so it's something like comments/:id/reply/:reply_id or comments/:id/reply/new.
Here's some great examples for nested attributes: http://guides.rubyonrails.org/routing.html#nested-resources
SECOND EDIT
Okay, I was a bit confused because typically you would have the form in new not in show. Either way I would be looking at the instance variables being passed in. How do your associations look?
if it's Post has_many :comments and Comment has_many :replies, then you can do something like this in your show actions:
def new
#post = Post.find(params[:post_id]
#comment = #post.comments.find(params[:comment_id]) #scopes your search to only the comments belonging to this post
#reply = #comment.replies.new
end
The more important point to get out of this is that each instance variable needs to be passed in. that being said, I'm not sure which ones are currently working for you
As far as create you should be doing something similar, creating through the associations. This rails magic handles all the foreign keys and assigning the id's etc:
def create
#post = Post.find(params[:post_id]
#comment = Comment.find(params[:comment_id])
#reply = #comment.replies.new(reply_params)
if #reply.save
# some logic
redirect_to wherever_path
else
# other logic
render :new
end
end
The more important point to get out of this is that each instance variable needs to be passed in. that being said, I'm not sure which ones are currently working for you
Let me know how this works!

Create association in Rails

I've got model Project and model User. I've got belongs_and_has_many in these. But now I need to tell Rails: this specific user belongs to this specific project. How can I do it in Project controller, and how can I call this method from project view? Thank you very much.
in project's*show.html.erb* I ve got:
<select id="user_select" name="user_select" class="input-large">
<% #users.each do |user| %>
<option><%= user.username %></options>
<% end %>
</select>
<!-- button to addfriend method here -->
And I need to call method "addfriend" from here with parameter from selection to associated project with this user :-/
Method addfiend in project controller:
def addfriend
#project = Project.find(params[:id])
#project.users << User.find(params[:user])
respond_to do |format|
format.html { redirect_to project, :notice => 'Added.' }
end
end
This would look something like that in your controller action:
#project = Project.create(:user_id => user_id)
while user_id is your foreign key (something you would probably want to pass from your view).
This code will be written in some controller action, and you would have to define a route for connecting a URL to this action.
Notice that once you call the action that runs this code you can access #project from your view.
You can read about routes here.
You can read about mvc in rails here.
You can read about associations here:
http://guides.rubyonrails.org/association_basics.html
If in model project, you have has_and_belongs_to_many :users, you project object has an implicit collection, users, that can be added to like any other collection, e.g.:
project.users << User.find(:first, :conditions => "name = 'foo'")

How to make a Controller Function call from Views Template in rails?

I am new to Rails and have a function in product_controller.rb
def detach
#product.photo = nil
#product.save
end
now I want to call this method from views file show.html.erb so the method get executed. How to do it ? I can see the 7 methods do get called through .find(params[id]) but that is also not clear to me.
You'll need to add a route, something like this in routes.rb:
resources :products do
member do
get 'detach' # /products/:id/detach
end
end
That will give you detach_product_path(#product) which you can use in your view. You'll probably also want a redirect in the detach method:
def detach
#product = Product.find(params[:id])
#product.photo = nil
if #product.save
redirect_to #product, notice: 'Photo was detached!'
end
end
Try changing as follow
<%= link_to 'detach_image', product_detach_path(#product) %>
I would suggest you to have a look at guides.rubyonrails.org/routing.html.
you can do as follow,
you can use match
match '/update_profile', :to => 'users#update_profile'
or
resources :users do
get 'update_profile', on: :member
end
and then you would definitely have method in your users controller
def update_profile
#user = User.find(params[:id])
if #user.save
redirect_to #user, notice: 'user updated successfully!'
end
end
I have fixed the Simon answer. However, you are still facing the problem because you are not passing the product with the path:
<%= link_to 'detach_image', detach_product_path %>
You need to pass the product to the action:
<%= link_to 'detach_image', detach_product_path(#product) %>
Otherwise, the Product.find(params[:id]) will not find any product, and the #product will get empty...
Edit to reply your questions:
1 - product_detach_path is a helper for the action detach in the controller product. There is also the product_detach_url, which does the same thing, but also includes the current host, port and path prefix. More details here.
However, it does not pass any param, so Product.find(params[:id]) cannot find the product. For this reason, you must specify what product are you trying to find. #product is defined in the show action, so it is available in your view, but you could send any other product for the detach action.... maybe the first one: product_detach_path(Product.first)
2 - the resources :products generates seven default routes: index, new, create, show, edit, update and destroy.
In order to add more routes to it, you can use member or collection. Basically, member will add a route to a product (products/1/detach), while collection will add a route to the controller, like index (products/detach). More information here.
I hope it helps...

Using the same "Voting" controller action for two different objects

I am following schneems's great intro to Rails tutorial on creating a Reddit clone, and want to expand the "voting" structure to work not only for questions, but for comments as well, and was having difficulty figuring out how to pass into the controller both question_id and comment_id so it could vote up or down accordingly, rather than restricting the usage to only question_id.
Currently, there is only a create function in my VotesController, defined as the following:
def create
#vote = Vote.where(:question_id => params[:vote][:question_id], :user_id => current_user.id).first #the question_id is baked right in..
if #vote
#vote.up = params[:vote][:up]
#vote.save
else
#vote = current_user.votes.create(params[:vote])
end
redirect_to :back
end
Thanks for your help!
Well, when you try to vote on a comment, that would mean that params[:vote] should contain a :comment_id instead of a :question_id, right?
So your where statement needs to either be
# for a question
where(:question_id => params[:vote][:question_id], :user_id => current_user.id)
# for a comment
where(:comment_id => params[:vote][:comment_id], :user_id => current_user.id)
You approach this in various ways, like by checking if params[:vote].has_key?(:question_id), but an easy option would be to use Hash#slice:
where(params[:vote].slice(:question_id, :comment_id).merge(:user_id => current_user.id))

Passing parameters for nested relationship

I am having trouble passing parameters
My application that is setup like this:
Fact belongs_to Source
Source has_many Facts
Source is nested under User in routes
I am using the Facts form to create the Source data. So I have getter and setter methods in the Facts model like this:
def source_name
source.try(:name)
end
def source_name=(name)
self.source = source.find_or_create_by_name(name) if name.present?
end
This is working great, but it is not setting the user_id for the parent User attribute. As a result, sources are created, but they are not associated with the User.
I have a hidden field with user_id in the form, but the user_id is still being set. What is the easiest way to pass and save the user_id so the nested relationship is set?
Here is the create method for the Source controller:
def create
#user = User.find(params[:user_id])
#source = #user.source.build(params[:source])
...
end
I think the problem is that you are creating source directly from the setter method in the Fact model. Unless you establish the chain by using something like build in the FactController, the user_id will not be set. What you are doing in SourceController needs to be done in the FactsController too. Also, it seems that the ids are set only for the immediate parent when you use the build command. You can try something as below:
def create
#source = current_user.sources.find_or_create_by_name(params["source_name"])
#fact = #source.facts.build(:user_id => #source.user_id)
....
end
Hope that helps.
If your user has a single Source, try the following as your create() method:
def create
#user = User.find params[:user_id]
#user.source = Source.new params[:source]
if #user.save
redirect_to #user, :flash => { :success => "Source updated!" }
else
flash[:error] = "Failed to update the source!"
render :action => "new"
end
end
Creating the Source as an attribute on the User object and then saving the User object should automatically associate the Source with the User.

Resources